C++

Come usare i modelli C++

Come usare i modelli C++

introduzione

Nella programmazione C++ di base, il tipo di dati, e.g., int o char, deve essere indicato in una dichiarazione o in una definizione. Un valore come 4 o 22 o -5 è un int. Un valore come "A" o "b" o "c" è un carattere. Il meccanismo del modello consente al programmatore di utilizzare un tipo generico per un insieme di tipi effettivi. Ad esempio, il programmatore può decidere di utilizzare l'identificatore T per int o char. È possibile che un algoritmo C++ abbia più di un tipo generico. Con, ad esempio, T per int o char, U può rappresentare il tipo float o pointer. Una classe, come la classe string o vector, è come un tipo di dati e gli oggetti istanziati sono come i valori del tipo di dati, che è la classe specificata. Quindi, il meccanismo del modello consente anche al programmatore di utilizzare un identificatore di tipo generico per un insieme di classi.

Un modello C++ crea un algoritmo indipendente dal tipo di dati utilizzati. Quindi, lo stesso algoritmo, con molte occorrenze dello stesso tipo, può utilizzare tipi diversi a esecuzioni diverse. Le entità di variabile, funzione, struttura e classe possono avere modelli. Questo articolo spiega come dichiarare i modelli, come definire i modelli e come applicarli in C++. Dovresti già avere conoscenza delle suddette entità per comprendere gli argomenti trattati in questo articolo.

tipi

Scalare

I tipi scalari sono void, bool, char, int, float e pointer.

Classi come tipi

Una classe particolare può essere considerata come un tipo e i suoi oggetti come possibili valori.

Un tipo generico rappresenta un insieme di tipi scalari. L'elenco dei tipi scalari è ampio. Il tipo int, ad esempio, ha altri tipi correlati, come short int, long int, ecc. Un tipo generico può anche rappresentare un insieme di classi.

Variabile

Un esempio di dichiarazione e definizione di un modello è il seguente:

modello
T pi = 3.14;

Prima di continuare, nota che questo tipo di istruzione non può apparire nella funzione main() o in qualsiasi ambito di blocco. La prima riga è la dichiarazione template-head, con il nome del tipo generico scelto dal programmatore, T. La riga successiva è la definizione dell'identificatore, pi, che è del tipo generico, T. La precisione, se la T è un int o un float o qualche altro tipo, può essere eseguita nella funzione C++ main() (o qualche altra funzione). Tale precisione sarà fatta con la variabile pi, e non con T.

La prima riga è la dichiarazione template-head. Questa dichiarazione inizia con la parola riservata, il modello e quindi le parentesi angolari aperte e chiuse. All'interno delle parentesi angolari, c'è almeno un identificatore di tipo generico, come T, sopra. Può esserci più di un identificatore di tipo generico, ciascuno preceduto dalla parola riservata, typename. Tali tipi generici in quella posizione sono chiamati parametri del modello.

La seguente istruzione può essere scritta in main() o in qualsiasi altra funzione:

cout << pi << '\n';

E la funzione visualizzerà 3.14. L'espressione pi decide il tipo esatto di T per la variabile pi. La specializzazione decide il particolare tipo di dati per il parametro template template. L'istanziazione è il processo interno C++ di creazione del tipo particolare, come float, in questo caso. Non confondere tra istanziare un parametro template e istanziare una classe. Nell'argomento del modello, molti tipi di dati possono avere un nome di tipo generico, mentre molte classi possono avere un nome di classe generico. Tuttavia, il nome di classe generico per le classi viene semplicemente indicato come una classe e non come un nome di classe. Inoltre, un valore sta a un tipo di dati, come int, come un oggetto istanziato sta a una classe, come la classe String.

Alla specializzazione, il tipo di dati scelto, come float, è posto tra parentesi angolari dopo la variabile. Se c'è più di un parametro template nella dichiarazione template-head, ci sarà un numero corrispondente di tipi di dati nello stesso ordine nell'espressione di specializzazione.

Nella specializzazione, un tipo è noto come argomento del modello. Non confondere tra questo e l'argomento della funzione per la chiamata di funzione.

Tipo predefinito

Se non viene fornito alcun tipo alla specializzazione, viene assunto il tipo predefinito. Quindi, dalla seguente espressione:

modello
U pi = "amore";
la visualizzazione da:
cout << pi<> << '\n';

è "amore" per il costante puntatore a char. Nota nella dichiarazione che U = const char*. Le parentesi angolari saranno vuote alla specializzazione (nessun tipo dato); il tipo effettivo è considerato un puntatore const a char, il tipo predefinito. Se durante la specializzazione fosse necessario un altro tipo, il nome del tipo verrebbe scritto tra parentesi angolari. Quando si desidera il tipo predefinito alla specializzazione, ripetere il tipo tra parentesi angolari è facoltativo, i.e., le parentesi angolari possono essere lasciate vuote.

Nota: il tipo predefinito può ancora essere modificato alla specializzazione con un tipo diverso.

struttura

L'esempio seguente mostra come un parametro template può essere utilizzato con una struttura:

modello struttura Età

T Giovanni = 11;
T Pietro = 12;
T Maria = 13;
T Gioia = 14;
;

Queste sono le età degli studenti in una classe (classe). La prima riga è la dichiarazione del modello. Il corpo tra parentesi è la definizione effettiva del modello. Le età possono essere emesse nella funzione main() con quanto segue:

Età grado 7;
cout << grade7.John << " << grade7.Mary << '\n';

L'uscita è: 11 13. La prima affermazione qui esegue la specializzazione. Nota come è stato realizzato. Dà anche un nome per un oggetto della struttura: grade7. La seconda istruzione ha normali espressioni di oggetti struct. Una struttura è come una classe. Qui, Ages è come un nome di classe, mentre grade7 è un oggetto della classe (struct).

Se alcune età sono intere e altre sono float, la struttura necessita di due parametri generici, come segue:

modello struttura Età

T Giovanni = 11;
U Pietro = 12.3;
T Maria = 13;
U Gioia = 14.6;
;

Un codice rilevante per la funzione main() è il seguente:

Età grado 7;
cout << grade7.John << " << grade7.Peter << '\n';

L'uscita è: 11 12.3. Alla specializzazione, l'ordine dei tipi (argomenti) deve corrispondere all'ordine dei tipi generici nella dichiarazione.

La dichiarazione del modello può essere separata dalla definizione, come segue:

modello struttura Età

T Giovanni;
U Pietro;
T Maria;
tu gioia;
;
Età grado7 = 11, 12.3, 13, 14.6;

Il primo segmento di codice è puramente una dichiarazione di un modello (non ci sono assegnazioni). Il secondo segmento di codice, che è solo un'istruzione, è la definizione dell'identificatore, grado7. Il lato sinistro è la dichiarazione dell'identificatore, grade7. Il lato destro è l'elenco degli inizializzatori, che assegna i valori corrispondenti ai membri della struttura. Il secondo segmento (istruzione) può essere scritto nella funzione main(), mentre il primo segmento rimane fuori dalla funzione main().

Non di tipo

Esempi di tipi non di dati includono int, pointer to object, pointer to function e auto type. Ci sono altri non tipi, che questo articolo non affronta. Un non-tipo è come un tipo incompleto, il cui valore è dato in seguito e non può essere modificato. Come parametro, inizia con un particolare non tipo, seguito da un identificatore. Il valore dell'identificatore è dato in seguito, alla specializzazione, e non può essere cambiato di nuovo (come una costante, il cui valore è dato in seguito). Il seguente programma lo illustra:

#includere
usando lo spazio dei nomi std;
modello struttura Età

T Giovanni = N;
U Pietro = 12.3;
T Maria = N;
U Gioia = 14.6;
;
intero principale()

Età grado 7;
cout << grade7.John << " << grade7.Joy << '\n';
restituisce 0;

Alla specializzazione, il primo tipo, int, nelle parentesi angolari c'è più per formalità, per assicurarsi che il numero e l'ordine dei parametri corrispondano al numero e all'ordine dei tipi (argomenti). Il valore di N è stato dato alla specializzazione. L'uscita è: 11 14.6.

Specializzazione parziale

Supponiamo che un template abbia quattro tipi generici e che, tra i quattro tipi, siano necessari due tipi predefiniti. Ciò può essere ottenuto utilizzando il costrutto di specializzazione parziale, che non utilizza l'operatore di assegnazione. Quindi, il costrutto di specializzazione parziale fornisce valori predefiniti a un sottoinsieme di tipi generici. Tuttavia, nello schema di specializzazione parziale, sono necessarie una classe di base (struct) e una classe di specializzazione parziale (struct). Il seguente programma illustra questo per un tipo generico su due tipi generici:

#includere
usando lo spazio dei nomi std;
//classe modello base
modello
struttura Età

;
//specializzazione parziale
modello
struttura Età

T1 Giovanni = 11;
galleggiante Pietro = 12.3;
T1 Maria = 13;
galleggiante Gioia = 14.6;
;
intero principale()

Età grado 7;
cout << grade7.John << " << grade7.Joy << '\n';
restituisce 0;

Identificare la dichiarazione della classe base e la sua definizione di classe parziale. La dichiarazione template-head della classe base ha tutti i parametri generici necessari. La dichiarazione template-head della classe di specializzazione parziale ha solo il tipo generico. C'è un ulteriore set di parentesi angolari usato nello schema che viene subito dopo il nome della classe nella definizione di specializzazione parziale. È ciò che effettivamente fa la specializzazione parziale. Ha il tipo predefinito e il tipo non predefinito, nell'ordine scritto nella classe base. Nota che al tipo predefinito può ancora essere assegnato un tipo diverso nella funzione main().

Il codice pertinente nella funzione main() può essere il seguente:

Età grado 7;
cout << grade7.John << " << grade7.Joy << '\n';

L'uscita è: 11 14.6.

Pacchetto parametri modello

Un pacchetto di parametri è un parametro di modello che accetta zero o più tipi generici di modello per i tipi di dati corrispondenti. Il parametro del pacchetto di parametri inizia con la parola riservata typename o class. Questo è seguito da tre punti e quindi dall'identificatore del pacchetto. Il seguente programma illustra come utilizzare un pacchetto di parametri modello con una struttura:

#includere
usando lo spazio dei nomi std;
modello struttura Età

int Giovanni = 11;
galleggiante Pietro = 12.3;
int Maria = 13;
galleggiante Gioia = 14.6;
;
intero principale()

Età grado B;
cout << gradeB.John << " << gradeB.Mary << '\n';
Età grado C;
cout << gradeC.Peter << " << gradeC.Joy << '\n';
Età gradoD;
cout << gradeD.John << " << gradeD.Joy << '\n';
Età<> grado A; //come predefinito
cout << gradeA.John << " << gradeA.Joy << '\n';
restituisce 0;

L'uscita è:

11 13
12.3 14.6
11 14.6
11 14.6

Modelli di funzioni

Le caratteristiche del modello sopra menzionate si applicano in modo simile ai modelli di funzione. Il seguente programma mostra una funzione con due parametri di template generici e tre argomenti:

#includere
usando lo spazio dei nomi std;
modello void func (T no, U cha, const char *str )

cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

intero principale()

func(12, '$', "500");
restituisce 0;

L'output è il seguente:

Ci sono 12 libri del valore di $ 500 nel negozio.

Separazione dal prototipo

La definizione della funzione può essere separata dal suo prototipo, come mostra il seguente programma:

#includere
usando lo spazio dei nomi std;
modello void func (T no, U cha, const char *str );
modello void func (T no, U cha, const char *str )

cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

intero principale()

func(12, '$', "500");
restituisce 0;

Nota: la dichiarazione del modello di funzione non può apparire nella funzione main() o in qualsiasi altra funzione.

sovraccarico

Il sovraccarico della stessa funzione può avvenire con diverse dichiarazioni template-head. Il seguente programma lo illustra:

#includere
usando lo spazio dei nomi std;
modello void func (T no, U cha, const char *str )

cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

modello void func (T no, const char *str )

cout << "There are " << no << " books worth $" << str << " in the store." << '\n';

intero principale()

func(12, '$', "500");
funzione(12, "500");
restituisce 0;

L'uscita è:

Ci sono 12 libri del valore di $ 500 nel negozio.

Ci sono 12 libri del valore di $ 500 nel negozio.

Modelli di classe

Le caratteristiche dei modelli sopra menzionati si applicano in modo simile ai modelli di classe. Il seguente programma è la dichiarazione, la definizione e l'uso di una classe semplice:

#includere
usando lo spazio dei nomi std;
classe TheCla

pubblico:
numero int;
carattere statico;
void func (char cha, const char *str)

cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

divertimento vuoto statico (char ch)

se (ch == 'a')
cout << "Official static member function" << '\n';

;
intero principale()

TheCla obj;
obj.numero = 12;
obj.func('$', "500");
restituisce 0;

L'output è il seguente:

Ci sono 12 libri del valore di $ 500 nel negozio.

Il seguente programma è il programma sopra con una dichiarazione template-head:

#includere
usando lo spazio dei nomi std;
modello classe TheCla

pubblico:
T numero;
statico U ch;
void func (U cha, const char *str)

cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

divertimento vuoto statico (U ch)

se (ch == 'a')
cout << "Official static member function" << '\n';

;
intero principale()

TheCla oggetto;
obj.numero = 12;
obj.func('$', "500");
restituisce 0;

Invece della parola typename nell'elenco dei parametri del modello, è possibile utilizzare la classe di parole. Notare la specializzazione nella dichiarazione dell'oggetto. L'output è sempre lo stesso:

Ci sono 12 libri del valore di $ 500 nel negozio.

Dichiarazione di separazione

La dichiarazione del modello di classe può essere separata dal codice della classe, come segue:

modello classe TheCla;
modello classe TheCla

pubblico:
T numero;
statico U ch;
void func (U cha, const char *str)

cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

divertimento vuoto statico (U ch)

se (ch == 'a')
cout << "Official static member function" << '\n';

;

Trattare con membri statici

Il programma seguente mostra come accedere a un membro di dati statici e a una funzione membro statico:

#includere
usando lo spazio dei nomi std;
modello classe TheCla

pubblico:
T numero;
statico U ch;
void func (U cha, const char *str)

cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

divertimento vuoto statico (U cha)

se (ch == 'a')
cout << "Official static member function" << cha << '\n';

;
modello U TheCla::ch = 'un';
intero principale()

TheCla::divertimento('.');
restituisce 0;

L'assegnazione di un valore a un membro di dati statici è una dichiarazione e non può essere in main(). Nota l'uso e le posizioni dei tipi generici e del tipo generico di dati nell'istruzione di assegnazione. Inoltre, si noti che la funzione membro dati statici è stata chiamata in main(), con i tipi di dati del modello effettivi. L'output è il seguente:

Funzione membro statico ufficiale.

Compilazione

La dichiarazione (intestazione) e la definizione di un modello devono essere in un unico file. Cioè, devono essere nella stessa unità di traduzione.

Conclusione

I modelli C++ rendono un algoritmo indipendente dal tipo di dati utilizzati. Le entità di variabile, funzione, struttura e classe possono avere modelli, che implicano dichiarazione e definizione. La creazione di un modello implica anche la specializzazione, ovvero quando un tipo generico assume un tipo effettivo. La dichiarazione e la definizione di un modello devono essere entrambe in un'unità di traduzione.

Come acquisire e riprodurre in streaming la tua sessione di gioco su Linux
In passato, giocare era considerato solo un hobby, ma con il tempo l'industria dei giochi ha visto una crescita enorme in termini di tecnologia e nume...
I migliori giochi da giocare con il tracciamento delle mani
Oculus Quest ha recentemente introdotto la grande idea del tracciamento manuale senza controller. Con un numero sempre crescente di giochi e attività ...
Come mostrare l'overlay OSD in app e giochi Linux a schermo intero
Giocare a giochi a schermo intero o utilizzare app in modalità a schermo intero senza distrazioni può tagliarti fuori dalle informazioni di sistema ri...