Aracılığıyla paylaş


Diğer adlar ve tür tanımları (C++)

Daha önce bildirilen bir tür için eş anlamlı olarak kullanılacak bir ad bildirmek için diğer ad bildirimi kullanabilirsiniz. (Bu mekanizma, kayıt dışı olarak tür diğer adı olarak da adlandırılır). Bu mekanizmayı, özel ayırıcılar için yararlı olabilecek bir diğer ad şablonu oluşturmak için de kullanabilirsiniz.

Sözdizimi

using identifier = type;

Açıklamalar

identifier
Diğer adın adı.

type
Diğer ad oluşturduğunuz tür tanımlayıcısı.

Diğer ad yeni bir tür sunmaz ve var olan bir tür adının anlamını değiştiremez.

Diğer adın en basit biçimi C++03 mekanizmasına typedef eşdeğerdir:

// C++11
using counter = long;

// C++03 equivalent:
// typedef long counter;

Bu formların her ikisi de türünde counterdeğişkenlerin oluşturulmasını sağlar. Daha kullanışlı bir şey için bunun std::ios_base::fmtflagsgibi bir tür diğer adı olabilir:

// C++11
using fmtfl = std::ios_base::fmtflags;

// C++03 equivalent:
// typedef std::ios_base::fmtflags fmtfl;

fmtfl fl_orig = std::cout.flags();
fmtfl fl_hex = (fl_orig & ~std::cout.basefield) | std::cout.showbase | std::cout.hex;
// ...
std::cout.flags(fl_hex);

Diğer adlar işlev işaretçileriyle de çalışır, ancak eşdeğer tür tanımından çok daha okunabilir:

// C++11
using func = void(*)(int);

// C++03 equivalent:
// typedef void (*func)(int);

// func can be assigned to a function pointer value
void actual_function(int arg) { /* some code */ }
func fptr = &actual_function;

Mekanizmanın typedef bir sınırlaması, şablonlarla çalışmamasıdır. Ancak, C++11'deki tür diğer ad söz dizimi diğer ad şablonlarının oluşturulmasını sağlar:

template<typename T> using ptr = T*;

// the name 'ptr<T>' is now an alias for pointer to T
ptr<int> ptr_int;

Örnek

Aşağıdaki örnekte bir diğer ad şablonunun özel ayırıcıyla (bu örnekte tamsayı vektör türü) nasıl kullanılacağı gösterilmektedir. Ana işlevsel kodunuzda karmaşık parametre listelerini gizlemek için uygun bir diğer ad oluşturmak için int herhangi bir türü yerine kullanabilirsiniz. Kodunuzun tamamında özel ayırıcıyı kullanarak okunabilirliği artırabilir ve yazım hatasının neden olduğu hataların ortaya çıkma riskini azaltabilirsiniz.

#include <stdlib.h>
#include <new>

template <typename T> struct MyAlloc {
    typedef T value_type;

    MyAlloc() { }
    template <typename U> MyAlloc(const MyAlloc<U>&) { }

    bool operator==(const MyAlloc&) const { return true; }
    bool operator!=(const MyAlloc&) const { return false; }

    T * allocate(const size_t n) const {
        if (n == 0) {
            return nullptr;
        }

        if (n > static_cast<size_t>(-1) / sizeof(T)) {
            throw std::bad_array_new_length();
        }

        void * const pv = malloc(n * sizeof(T));

        if (!pv) {
            throw std::bad_alloc();
        }

        return static_cast<T *>(pv);
    }

    void deallocate(T * const p, size_t) const {
        free(p);
    }
};

#include <vector>
using MyIntVector = std::vector<int, MyAlloc<int>>;

#include <iostream>

int main ()
{
    MyIntVector foov = { 1701, 1764, 1664 };

    for (auto a: foov) std::cout << a << " ";
    std::cout << "\n";

    return 0;
}
1701 1764 1664

Tür tanımları

Bir typedef bildirim, kapsamı içinde bildirimin tür bildirimi bölümü tarafından verilen tür için bir eş anlamlıya dönüşen bir ad tanıtır.

Typedef bildirimlerini, dil tarafından önceden tanımlanmış olan türler veya bildirdiğiniz türler için daha kısa veya daha anlamlı adlar oluşturmak için kullanabilirsiniz. Typedef adları, değişebilecek uygulama ayrıntılarını kapsüllemenize olanak sağlar.

, , structunionve enum bildirimlerinden farklı olarakclass, typedef bildirimler yeni türler sunmaz; var olan türler için yeni adlar ekler.

kullanılarak typedef bildirilen adlar diğer tanımlayıcılarla aynı ad alanını kaplar (deyim etiketleri dışında). Bu nedenle, sınıf türü bildirimi dışında daha önce bildirilen bir adla aynı tanımlayıcıyı kullanamazlar. Aşağıdaki örneği inceleyin:

// typedef_names1.cpp
// C2377 expected
typedef unsigned long UL;   // Declare a typedef name, UL.
int UL;                     // C2377: redefined.

Diğer tanımlayıcılarla ilgili ad gizleme kuralları, kullanılarak typedefbildirilen adların görünürlüğünü de yönetir. Bu nedenle, aşağıdaki örnek C++'da geçerlidir:

// typedef_names2.cpp
typedef unsigned long UL;   // Declare a typedef name, UL
int main()
{
   unsigned int UL;   // Redeclaration hides typedef name
}

// typedef UL back in scope

Başka bir ad gizleme örneği:

// typedef_specifier1.cpp
typedef char FlagType;

int main()
{
}

void myproc( int )
{
    int FlagType;
}

Bir yerel kapsam tanımlayıcısını ile aynı ada typedefgöre bildirdiğinizde veya aynı kapsamda veya iç kapsamdaki bir yapı veya birleşimin üyesini bildirdiğinizde, tür tanımlayıcısı belirtilmelidir. Örnek:

typedef char FlagType;
const FlagType x;

Tanımlayıcının, yapı üyesinin FlagType veya birleşim üyesinin adını yeniden kullanmak için türü sağlanmalıdır:

const int FlagType;  // Type specifier required

Bunu söylemek yeterli değildir

const FlagType;      // Incomplete specification

çünkü , FlagType yeniden işlenen bir tanımlayıcı değil, türün bir parçası olarak alınır. Bu bildirim, aşağıdakine benzer şekilde yasa dışı bir bildirim olarak alınır:

int;  // Illegal declaration

İşaretçi, işlev ve dizi türleri dahil olmak üzere ile typedefherhangi bir türü bildirebilirsiniz. Tanımın bildirimle aynı görünürlüğe sahip olduğu sürece, yapıyı veya birleşim türünü tanımlamadan önce bir yapı veya birleşim türü işaretçisi için tür tanımı adı bildirebilirsiniz.

Örnekler

Bildirimlerin typedef bir kullanımı, bildirimleri daha düzgün ve kompakt hale getirmektir. Örnek:

typedef char CHAR;          // Character type.
typedef CHAR * PSTR;        // Pointer to a string (char *).
PSTR strchr( PSTR source, CHAR target );
typedef unsigned long ulong;
ulong ul;     // Equivalent to "unsigned long ul;"

Aynı bildirimde temel ve türetilmiş türleri belirtmek için kullanmak typedef için bildirimcileri virgülle ayırabilirsiniz. Örnek:

typedef char CHAR, *PSTR;

Aşağıdaki örnek, değer döndürmeden iki int bağımsız değişkeni alan bir işlevin türünü DRAWF sağlar:

typedef void DRAWF( int, int );

Yukarıdaki typedef ifadeden sonra bildirimi

DRAWF box;

bildirimine eşdeğer olacaktır

void box( int, int );

typedef genellikle kullanıcı tanımlı türleri bildirmek ve adlandırmak için ile struct birleştirilir:

// typedef_specifier2.cpp
#include <stdio.h>

typedef struct mystructtag
{
    int   i;
    double f;
} mystruct;

int main()
{
    mystruct ms;
    ms.i = 10;
    ms.f = 0.99;
    printf_s("%d   %f\n", ms.i, ms.f);
}
10   0.990000

Tür tanımlarının yeniden dikte edilmesi

Bildirimi, typedef aynı türe başvurmak için aynı adı yeniden eklemek için kullanılabilir. Örnek:

Kaynak dosya file1.h:

// file1.h
typedef char CHAR;

Kaynak dosya file2.h:

// file2.h
typedef char CHAR;

Kaynak dosya prog.cpp:

// prog.cpp
#include "file1.h"
#include "file2.h"   // OK

Dosyaprog.cpp, her ikisi de adı CHARiçin bildirimler içeren iki üst bilgi dosyası içerirtypedef. Her iki bildirim de aynı türe başvurduğu sürece, böyle bir yeniden bildirim kabul edilebilir.

typedef daha önce farklı bir tür olarak bildirilen bir adı yeniden tanımlayamaz. Şu alternatifi file2.hgöz önünde bulundurun:

// file2.h
typedef int CHAR;     // Error

Derleyici, farklı bir türe başvurmak için adı CHAR yeniden ekleme girişimi nedeniyle içinde bir hata prog.cpp döndürür. Bu ilke aşağıdaki gibi yapılara genişletir:

typedef char CHAR;
typedef CHAR CHAR;      // OK: redeclared as same type

typedef union REGS      // OK: name REGS redeclared
{                       //  by typedef name with the
    struct wordregs x;  //  same meaning.
    struct byteregs h;
} REGS;

C++ ve C'de tür tanımları

Tanımlayıcının typedef sınıf türleriyle kullanılması, ansi C'nin bildirimlerde typedef adsız yapıları bildirme uygulaması nedeniyle büyük ölçüde desteklenir. Örneğin, birçok C programcısı aşağıdaki deyimi kullanır:

// typedef_with_class_types1.cpp
// compile with: /c
typedef struct {   // Declare an unnamed structure and give it the
                   // typedef name POINT.
   unsigned x;
   unsigned y;
} POINT;

Böyle bir bildirimin avantajı, aşağıdaki gibi bildirimleri etkinleştirmesidir:

POINT ptOrigin;

Onun yerine:

struct point_t ptOrigin;

C++ dilinde adlar ve gerçek türler (, , ve enum anahtar sözcükleriyle classbildirilir) arasındaki typedef fark daha unionfarklıdır. struct C deyiminde adsız bir yapı bildirme uygulaması hala işe yarasa da, C'de olduğu gibi herhangi bir typedef gösterimi yarar sağlamaz.

// typedef_with_class_types2.cpp
// compile with: /c /W1
typedef struct {
   int POINT();
   unsigned x;
   unsigned y;
} POINT;

Yukarıdaki örnek, adlandırılmamış sınıf söz dizimini kullanarak adlı POINT bir sınıf typedef bildirir. POINT sınıf adı olarak değerlendirilir; ancak, aşağıdaki kısıtlamalar bu şekilde tanıtılan adlar için geçerlidir:

  • Ad (eş anlamlı) bir , structveya union ön ekinin classardından görünemez.

  • Ad, bir sınıf bildirimi içinde oluşturucu veya yıkıcı adı olarak kullanılamaz.

Özetle, bu söz dizimi devralma, oluşturma veya yok etme mekanizması sağlamaz.