Sdílet prostřednictvím


Aliasy a definice Typedef (C++)

Deklaraci aliasu můžete použít k deklarování názvu, který se má použít jako synonymum pro dříve deklarovaný typ. (Tento mechanismus se také označuje jako neformálně jako alias typu). Pomocí tohoto mechanismu můžete také vytvořit šablonu aliasu, která může být užitečná pro vlastní alokátory.

Syntaxe

using identifier = type;

Poznámky

identifikátor
Název aliasu.

type
Identifikátor typu, pro který vytváříte alias.

Alias nezavádí nový typ a nemůže změnit význam existujícího názvu typu.

Nejjednodušší forma aliasu je ekvivalentem typedef mechanismu z C++03:

// C++11
using counter = long;

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

Oba tyto formuláře umožňují vytváření proměnných typu counter. Něco užitečnějšího by byl alias typu podobný tomuto:std::ios_base::fmtflags

// 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);

Aliasy také fungují s ukazateli funkcí, ale jsou mnohem čitelnější než ekvivalentní definice typedef:

// 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;

Omezení typedef mechanismu spočívá v tom, že nefunguje se šablonami. Syntaxe aliasu typu v jazyce C++11 však umožňuje vytváření šablon aliasů:

template<typename T> using ptr = T*;

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

Příklad

Následující příklad ukazuje použití šablony aliasu s vlastním alokátorem – v tomto případě typu celočíselného vektoru. Pokud chcete vytvořit pohodlný alias pro skrytí složitých seznamů parametrů v hlavním funkčním kódu, můžete nahradit libovolný typ int . Pomocí vlastního alokátoru v celém kódu můžete zlepšit čitelnost a snížit riziko zavedení chyb způsobených překlepy.

#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

Typedefs

Deklarace typedef zavádí název, který se v rámci jeho oboru stane synonymem pro typ zadaný částí deklarace typu deklarace.

Deklarace typedef můžete použít k vytvoření kratších nebo smysluplnějších názvů pro typy, které jsou již definovány jazykem nebo pro typy, které jste deklarovali. Názvy typedef umožňují zapouzdřit podrobnosti implementace, které se mohou změnit.

Na rozdíl od classdeklarací , , structuniona enum deklarací typedef deklarace nezavádějí nové typy; zavádějí nové názvy pro existující typy.

Názvy deklarované pomocí typedef zabírají stejný obor názvů jako ostatní identifikátory (kromě popisků příkazů). Proto nemohou použít stejný identifikátor jako dříve deklarovaný název, s výjimkou deklarace typu třídy. Představte si následující příklad:

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

Pravidla skrývání názvů, která se týkají jiných identifikátorů, také řídí viditelnost názvů deklarovaných pomocí typedef. Následující příklad je proto v jazyce C++ platný:

// 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

Další instance skrytí názvu:

// typedef_specifier1.cpp
typedef char FlagType;

int main()
{
}

void myproc( int )
{
    int FlagType;
}

Když deklarujete identifikátor místního oboru stejným názvem jako nebo typedefkdyž deklarujete člen struktury nebo sjednocení ve stejném oboru nebo ve vnitřním oboru, musí být specifikátor typu zadán. Příklad:

typedef char FlagType;
const FlagType x;

Pro opětovné použití názvu FlagType pro identifikátor, člen struktury nebo člen sjednocení musí být určen typ:

const int FlagType;  // Type specifier required

Není to dostatečné k tomu, abyste řekli

const FlagType;      // Incomplete specification

FlagType protože se považuje za součást typu, nikoli identifikátor, který je předefinován. Toto prohlášení se považuje za nezákonné prohlášení, podobně jako:

int;  // Illegal declaration

Můžete deklarovat libovolný typ, typedefvčetně ukazatele, funkce a typů polí. Je možné deklarovat název typedef pro ukazatel na typ struktury nebo sjednocení před definováním typu struktury nebo sjednocení, pokud má definice stejnou viditelnost jako deklarace.

Příklady

Jedním z použití typedef deklarací je, aby deklarace byly jednotnější a kompaktnější. Příklad:

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;"

typedef Chcete-li určit základní a odvozené typy ve stejné deklaraci, můžete deklarátory oddělit čárkami. Příklad:

typedef char CHAR, *PSTR;

Následující příklad poskytuje typ DRAWF pro funkci nevracející žádnou hodnotu a přijímající dva celočíselné argumenty:

typedef void DRAWF( int, int );

Za výše uvedeným typedef příkazem deklarace

DRAWF box;

ekvivalentní deklaraci

void box( int, int );

typedef často se kombinuje s struct deklarovat a pojmenovat uživatelem definované typy:

// 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

Redeclaration of typedefs

Deklarace typedef se dá použít k opětovnému pojmenování stejného názvu, aby odkazovat na stejný typ. Příklad:

Zdrojový soubor file1.h:

// file1.h
typedef char CHAR;

Zdrojový soubor file2.h:

// file2.h
typedef char CHAR;

Zdrojový soubor prog.cpp:

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

Soubor prog.cpp obsahuje dva soubory hlaviček, z nichž oba obsahují typedef deklarace pro název CHAR. Pokud obě tyto deklarace odkazují na stejný typ, je taková změna deklarace přijatelná.

Nelze typedef předefinovat název, který byl dříve deklarován jako jiný typ. Zvažte tuto alternativu file2.h:

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

Kompilátor vydá chybu prog.cpp kvůli pokusu o opětovné pojmenování názvu CHAR , aby odkazoval na jiný typ. Tato zásada se vztahuje na konstrukce, jako jsou:

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;

typedefs v C++ vs. C

Použití specifikátoru typedef s typy tříd je podporováno z velké části z důvodu praxe ANSI C deklarování nepojmenovaných struktur v typedef deklaracích. Například mnoho programátorů jazyka C používá následující idiom:

// 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;

Výhodou takovéto deklarace je, že umožňuje deklarace, jako jsou:

POINT ptOrigin;

místo:

struct point_t ptOrigin;

V jazyce C++ je rozdíl mezi typedef názvy a skutečnými typy (deklarován pomocí class, structunion, a enum klíčových slov) odlišnější. I když c postup deklarování beznázvové struktury v typedef příkazu stále funguje, neposkytuje žádné notační výhody, jak to dělá v jazyce C.

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

Předchozí příklad deklaruje třídu pojmenovanou POINT pomocí syntaxe nepojmenované třídy typedef . POINT je považován za název třídy; Následující omezení se však vztahují na názvy zavedené tímto způsobem:

  • Název (synonymum) se nemůže zobrazit za symbolem , structnebo union předponouclass.

  • Název nelze použít jako konstruktor nebo název destruktoru v rámci deklarace třídy.

V souhrnu tato syntaxe neposkytuje žádný mechanismus dědičnosti, konstrukce nebo zničení.