Aliase und Typedefs (C++)
Sie können eine Aliasdeklaration verwenden, um einen Namen zu deklarieren, der als Synonym für einen zuvor deklarierten Typ verwendet werden soll. (Dieser Mechanismus wird auch informell als Typalias bezeichnet). Sie können diesen Mechanismus auch verwenden, um eine Aliasvorlage zu erstellen, die für benutzerdefinierte Zuweisungen nützlich sein kann.
Syntax
using identifier = type;
Hinweise
identifier
Der Name des Alias.
type
Der Typbezeichner, für den Sie einen Alias erstellen.
Ein Alias führt keinen neuen Typ ein und kann die Bedeutung eines vorhandenen Typnamens nicht ändern.
Die einfachste Form eines Alias entspricht dem typedef
Mechanismus von C++03:
// C++11
using counter = long;
// C++03 equivalent:
// typedef long counter;
Beide Formulare ermöglichen die Erstellung von Variablen vom Typ counter
. Nützlicherer wäre ein Typalias wie dieser für 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);
Aliase funktionieren auch mit Funktionszeigern, sind aber wesentlich besser lesbar als die entsprechende 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;
Eine Einschränkung des typedef
Mechanismus besteht darin, dass er nicht mit Vorlagen funktioniert. Die Typaliassyntax in C++11 ermöglicht jedoch die Erstellung von Aliasvorlagen:
template<typename T> using ptr = T*;
// the name 'ptr<T>' is now an alias for pointer to T
ptr<int> ptr_int;
Beispiel
Das folgende Beispiel zeigt die Verwendung einer Aliasvorlage mit einer benutzerdefinierten Zuweisung, in diesem Fall einem ganzzahligen Vektortyp. Sie können jeden beliebigen Typ int
ersetzen, um einen geeigneten Alias zu erstellen, um die komplexen Parameterlisten in Ihrem Standard Funktionalen Code auszublenden. Wenn Sie den benutzerdefinierten Zuweisungscode im gesamten Code verwenden, können Sie die Lesbarkeit verbessern und das Risiko verringern, dass Fehler auftreten, die durch Tippfehler verursacht werden.
#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
Eine typedef
Deklaration führt einen Namen ein, der innerhalb seines Gültigkeitsbereichs zu einem Synonym für den Typ wird, der vom Typdeklarationsteil der Deklaration angegeben wird.
Sie können typedef-Deklarationen verwenden, um kürzere oder aussagekräftigere Namen für Typen zu erstellen, die bereits von der Sprache definiert wurden, oder für Typen, die Sie deklariert haben. Mithilfe von typedef-Namen können Sie die Implementierungsdetails kapseln, die sich möglicherweise ändern.
Im Gegensatz zu den class
enum
struct
union
Deklarationen führen Deklarationen typedef
keine neuen Typen ein; sie führen neue Namen für vorhandene Typen ein.
Namen, die mit typedef
demselben Namespace deklariert wurden wie andere Bezeichner (mit Ausnahme von Anweisungsbezeichnungen). Daher können sie nicht denselben Bezeichner wie ein zuvor deklarierter Name verwenden, außer in einer Klassentypdeklaration. Betrachten Sie das folgende Beispiel:
// typedef_names1.cpp
// C2377 expected
typedef unsigned long UL; // Declare a typedef name, UL.
int UL; // C2377: redefined.
Die Regeln zum Ausblenden von Namen, die sich auf andere Bezeichner beziehen, regeln auch die Sichtbarkeit von Namen, die mithilfe typedef
deklariert werden. Deshalb ist das folgenden Beispiel in C++ zulässig:
// 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
Eine andere Instanz des Ausblendens von Namen:
// typedef_specifier1.cpp
typedef char FlagType;
int main()
{
}
void myproc( int )
{
int FlagType;
}
Wenn Sie einen lokalen Bereichsbezeichner mit demselben Namen wie ein typedef
, oder wenn Sie ein Element einer Struktur oder Vereinigung im selben Bereich oder in einem inneren Bereich deklarieren, muss der Typbezeichner angegeben werden. Beispiel:
typedef char FlagType;
const FlagType x;
Um den FlagType
-Namen für einen Bezeichner, einen Strukturmember oder einen Unionsmember wiederzuverwenden, muss der Typ angegeben werden:
const int FlagType; // Type specifier required
Folgendes ist nicht ausreichend:
const FlagType; // Incomplete specification
da der FlagType
Teil des Typs ist, nicht ein Bezeichner, der neu deklariert wird. Diese Erklärung wird als unzulässige Erklärung angenommen, ähnlich wie:
int; // Illegal declaration
Sie können einen beliebigen Typ mit typedef
deklarieren, einschließlich Zeiger-, Funktions- und Arraytypen. Sie können einen typedef-Namen für einen Zeiger auf einen Struktur- oder einen Union-Typ deklarieren, bevor Sie den Struktur- oder Union-Typ definieren, solange die Definition die gleiche Sichtbarkeit wie die Deklaration aufweist.
Beispiele
Eine Verwendung von typedef
Deklarationen besteht darin, Deklarationen einheitlicher und kompakter zu gestalten. Beispiel:
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
Um grundlegende und abgeleitete Typen in derselben Deklaration anzugeben, können Sie Deklaratoren durch Kommas trennen. Beispiel:
typedef char CHAR, *PSTR;
Im folgenden Beispiel wird der Typ DRAWF
für eine Funktion bereitgestellt, die keinen Wert zurückgibt und zwei int-Argumente akzeptiert:
typedef void DRAWF( int, int );
Nach der obigen typedef
Anweisung, die Deklaration
DRAWF box;
dieser Deklaration:
void box( int, int );
typedef
wird häufig mit struct
dem Deklarieren und Benennen von benutzerdefinierten Typen kombiniert:
// 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
Neudeklarierung von TypeDefs
Die typedef
Deklaration kann verwendet werden, um denselben Namen neu einzuschließen, um auf denselben Typ zu verweisen. Beispiel:
Quelldatei file1.h
:
// file1.h
typedef char CHAR;
Quelldatei file2.h
:
// file2.h
typedef char CHAR;
Quelldatei prog.cpp
:
// prog.cpp
#include "file1.h"
#include "file2.h" // OK
Die Datei prog.cpp
enthält zwei Headerdateien, die beide Deklarationen für den Namen CHAR
enthaltentypedef
. Solange die beiden Deklarationen auf denselben Typ verweisen, ist eine solche Neudeklaration zulässig.
Ein typedef
Name kann nicht neu definiert werden, der zuvor als anderer Typ deklariert wurde. Erwägen Sie diese Alternative file2.h
:
// file2.h
typedef int CHAR; // Error
Der Compiler gibt einen Fehler prog.cpp
aufgrund des Versuchs aus, den Namen CHAR
neu zu deklarieren, um auf einen anderen Typ zu verweisen. Diese Richtlinie erstreckt sich auf Konstrukte wie:
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 in C++ vs. C
Die Verwendung des typedef
Bezeichners mit Klassentypen wird größtenteils aufgrund der ANSI C-Praxis unterstützt, nicht benannte Strukturen in typedef
Deklarationen zu deklarieren. Viele C-Programmierer verwenden z. B. den folgenden 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;
Der Vorteil einer solchen Deklaration ist, das Deklarationen wie folgt ermöglicht werden:
POINT ptOrigin;
Anstelle von:
struct point_t ptOrigin;
In C++ ist der Unterschied zwischen typedef
Namen und realen Typen (deklariert mit den class
, struct
, union
und enum
Schlüsselwort (keyword)s) eindeutiger. Obwohl die C-Praxis, eine namenslose Struktur in einer typedef
Anweisung zu deklarieren, weiterhin funktioniert, bietet sie keine notationalen Vorteile wie in C.
// typedef_with_class_types2.cpp
// compile with: /c /W1
typedef struct {
int POINT();
unsigned x;
unsigned y;
} POINT;
Im vorherigen Beispiel wird eine Klasse mit der Syntax der nicht benannten Klasse typedef
deklariertPOINT
. POINT
wird als Klassenname behandelt. Es gelten jedoch folgende Einschränkungen für Namen, die auf diese Weise eingeführt werden:
Der Name (das Synonym) kann nach einem
class
,struct
oderunion
präfix nicht angezeigt werden.Der Name kann nicht als Konstruktor- oder Destruktorname innerhalb einer Klassendeklaration verwendet werden.
Zusammenfassend bietet diese Syntax keinen Mechanismus für Vererbung, Konstruktion oder Zerstörung.
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für