Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
È possibile usare una dichiarazione alias per dichiarare un nome da usare come sinonimo di un tipo dichiarato in precedenza. Questo meccanismo viene anche definito in modo informale come alias di tipo. È anche possibile usare questo meccanismo per creare un modello di alias, che può essere utile per gli allocatori personalizzati.
Sintassi
using identifier = type;
Osservazioni:
identificatore
Nome dell'alias.
type
Identificatore del tipo per cui si sta creando un alias.
Un alias non introduce un nuovo tipo e non può modificare il significato di un nome di tipo esistente.
La forma più semplice di un alias equivale al typedef
meccanismo di C++03:
// C++11
using counter = long;
// C++03 equivalent:
// typedef long counter;
Entrambi questi moduli consentono la creazione di variabili di tipo counter
. Un'operazione particolarmente utile è un alias di tipo come questo per 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);
Gli alias funzionano anche con i puntatori a funzione, ma sono molto più leggibili rispetto al typedef equivalente:
// 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;
Una limitazione del typedef
meccanismo è che non funziona con i modelli. Tuttavia, la sintassi di alias di tipo in C++11 consente la creazione di modelli di alias:
template<typename T> using ptr = T*;
// the name 'ptr<T>' is now an alias for pointer to T
ptr<int> ptr_int;
Esempio
L'esempio seguente illustra come usare un modello di alias con un allocatore personalizzato, in questo caso un tipo intero vettoriale. È possibile sostituire qualsiasi tipo per int
creare un alias pratico per nascondere gli elenchi di parametri complessi nel codice funzionale principale. Usando l'allocatore personalizzato in tutto il codice, è possibile migliorare la leggibilità e ridurre il rischio di introdurre bug causati da errori di digitazione.
#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
Typedef
Una typedef
dichiarazione introduce un nome che, all'interno dell'ambito, diventa un sinonimo del tipo specificato dalla parte di dichiarazione di tipo della dichiarazione .
È possibile usare le dichiarazioni typedef per costruire nomi più brevi o più significativi per i tipi già definiti dal linguaggio o per i tipi dichiarati. I nomi di typedef consentono di incapsulare dettagli di implementazione che possono cambiare.
A differenza delle class
dichiarazioni , struct
, union
e enum
, typedef
le dichiarazioni non introducono nuovi tipi, ma introducono nuovi nomi per i tipi esistenti.
I nomi dichiarati usando typedef
occupano lo stesso spazio dei nomi degli altri identificatori (ad eccezione delle etichette delle istruzioni). Pertanto, non possono usare lo stesso identificatore di un nome dichiarato in precedenza, tranne in una dichiarazione di tipo classe. Si consideri l'esempio seguente:
// typedef_names1.cpp
// C2377 expected
typedef unsigned long UL; // Declare a typedef name, UL.
int UL; // C2377: redefined.
Le regole di nascondere il nome relative ad altri identificatori regolano anche la visibilità dei nomi dichiarati tramite typedef
. Di conseguenza, l'esempio seguente è valido in C++.
// 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
Un'altra istanza del nome nascosta:
// typedef_specifier1.cpp
typedef char FlagType;
int main()
{
}
void myproc( int )
{
int FlagType;
}
Quando si dichiara un identificatore di ambito locale con lo stesso nome di un typedef
oggetto o quando si dichiara un membro di una struttura o di un'unione nello stesso ambito o in un ambito interno, è necessario specificare l'identificatore di tipo. Ad esempio:
typedef char FlagType;
const FlagType x;
Per riutilizzare il nome FlagType
per un identificatore, un membro della struttura o un membro dell'unione, deve essere fornito il tipo:
const int FlagType; // Type specifier required
Non è sufficiente dire
const FlagType; // Incomplete specification
poiché l'oggetto FlagType
viene preso come parte del tipo, non un identificatore che viene dichiarato di nuovo. Questa dichiarazione viene considerata come una dichiarazione non valida, simile alla seguente:
int; // Illegal declaration
È possibile dichiarare qualsiasi tipo con typedef
, inclusi i tipi puntatore, funzione e matrice. È possibile dichiarare un nome di typedef per un puntatore a un tipo di unione o di struttura prima di definire il tipo di struttura o di unione, purché la definizione abbia la stessa visibilità della dichiarazione.
Esempi
Un uso delle typedef
dichiarazioni consiste nel rendere le dichiarazioni più uniformi e compattate. Ad esempio:
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;"
Per usare typedef
per specificare tipi fondamentali e derivati nella stessa dichiarazione, è possibile separare i dichiaratori con virgole. Ad esempio:
typedef char CHAR, *PSTR;
L'esempio seguente fornisce il tipo DRAWF
per una funzione che non restituisce alcun valore e accetta due argomenti int:
typedef void DRAWF( int, int );
Dopo l'istruzione precedente typedef
, la dichiarazione
DRAWF box;
sarà equivalente alla dichiarazione
void box( int, int );
typedef
viene spesso combinato con struct
per dichiarare e assegnare un nome ai tipi definiti dall'utente:
// 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
La typedef
dichiarazione può essere usata per ripetere lo stesso nome per fare riferimento allo stesso tipo. Ad esempio:
file1.h
File di origine :
// file1.h
typedef char CHAR;
file2.h
File di origine :
// file2.h
typedef char CHAR;
prog.cpp
File di origine :
// prog.cpp
#include "file1.h"
#include "file2.h" // OK
Il file prog.cpp
include due file di intestazione, entrambi contenenti typedef
dichiarazioni per il nome CHAR
. Se entrambe le dichiarazioni si riferiscono allo stesso tipo, tale ridichiarazione è accettabile.
Un typedef
oggetto non può ridefinire un nome dichiarato in precedenza come tipo diverso. Si consideri questa alternativa file2.h
:
// file2.h
typedef int CHAR; // Error
Il compilatore genera un errore in prog.cpp
a causa del tentativo di ripetere il nome CHAR
per fare riferimento a un tipo diverso. Questo criterio si estende a costrutti come:
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;
typedef in C++ e C
L'uso dell'identificatore typedef
con i tipi di classe è supportato in gran parte a causa della pratica ANSI C di dichiarare strutture senza nome nelle typedef
dichiarazioni. Ad esempio, molti programmatori C usano il linguaggio seguente:
// 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;
Il vantaggio di questo tipo di dichiarazione è che consente dichiarazioni quali:
POINT ptOrigin;
invece di:
struct point_t ptOrigin;
In C++, la differenza tra typedef
nomi e tipi reali (dichiarati con le class
parole chiave , struct
union
, e enum
) è più distinta. Anche se la pratica C di dichiarare una struttura senza nome in un'istruzione typedef
funziona ancora, non offre vantaggi di notazione così come in C.
// typedef_with_class_types2.cpp
// compile with: /c /W1
typedef struct {
int POINT();
unsigned x;
unsigned y;
} POINT;
Nell'esempio precedente viene dichiarata una classe denominata POINT
usando la sintassi della classe typedef
senza nome. POINT
viene considerato come un nome di classe; tuttavia, le restrizioni seguenti vengono applicate ai nomi introdotti nel modo seguente:
Il nome (sinonimo) non può essere visualizzato dopo un
class
prefisso ,struct
ounion
.Il nome non può essere usato come nome di costruttore o distruttore all'interno di una dichiarazione di classe.
In sintesi, questa sintassi non fornisce alcun meccanismo per l'ereditarietà, la costruzione o la distruzione.