Einführung
In der grundlegenden C++-Programmierung ist der Datentyp, z.G., int oder char, muss in einer Deklaration oder Definition angegeben werden. Ein Wert wie 4 oder 22 oder -5 ist ein int. Ein Wert wie 'A' oder 'b' oder 'c' ist ein char. Der Template-Mechanismus ermöglicht es dem Programmierer, einen generischen Typ für eine Reihe von tatsächlichen Typen zu verwenden. Zum Beispiel kann der Programmierer entscheiden, den Bezeichner T für int oder char . zu verwenden. Es ist möglich, dass ein C++-Algorithmus mehr als einen generischen Typ hat. Mit beispielsweise T für int oder char kann U für den Float- oder Pointer-Typ stehen. Eine Klasse, wie die String- oder Vektorklasse, ist wie ein Datentyp, und die instanziierten Objekte sind wie Werte des Datentyps, der die angegebene Klasse ist. Der Template-Mechanismus ermöglicht es dem Programmierer also auch, einen generischen Typbezeichner für eine Reihe von Klassen zu verwenden.
Eine C++-Vorlage erstellt einen Algorithmus unabhängig von der Art der verwendeten Daten. Derselbe Algorithmus mit vielen Vorkommen desselben Typs kann also unterschiedliche Typen bei verschiedenen Ausführungen verwenden. Die Entitäten von Variable, Funktion, Struktur und Klasse können Vorlagen haben. In diesem Artikel wird erläutert, wie Sie Vorlagen deklarieren, Vorlagen definieren und in C anwenden++. Sie sollten bereits über Kenntnisse der oben genannten Entitäten verfügen, um die in diesem Artikel behandelten Themen zu verstehen.
Typen
Skalar
Die Skalartypen sind void, bool, char, int, float und pointer.
Klassen als Typen
Eine bestimmte Klasse kann als Typ und ihre Objekte als mögliche Werte betrachtet werden.
Ein generischer Typ repräsentiert eine Menge von skalaren Typen. Die Liste der Skalartypen ist umfangreich. Der int-Typ hat beispielsweise andere verwandte Typen wie short int, long int usw. Ein generischer Typ kann auch eine Menge von Klassen darstellen.
Variable
Ein Beispiel für eine Vorlagendeklaration und -definition ist wie folgt:
VorlageTpi = 3.14;
Bevor Sie fortfahren, beachten Sie, dass diese Art von Anweisung nicht in der main()-Funktion oder in einem Blockbereich vorkommen kann. Die erste Zeile ist die Template-Head-Deklaration mit dem vom Programmierer gewählten generischen Typnamen T. Die nächste Zeile ist die Definition des Bezeichners pi, der vom generischen Typ T . ist. Die Genauigkeit, ob das T ein Int oder ein Float oder ein anderer Typ ist, kann in der C++-Funktion main() (oder einer anderen Funktion) vorgenommen werden. Eine solche Genauigkeit wird mit der Variablen pi erreicht und nicht mit T.
Die erste Zeile ist die Template-Head-Deklaration. Diese Deklaration beginnt mit dem reservierten Wort, der Vorlage und dann den offenen und geschlossenen spitzen Klammern. Innerhalb der spitzen Klammern gibt es mindestens einen generischen Typbezeichner, z. B. T, oben,. Es kann mehr als einen generischen Typbezeichner geben, wobei jedem das reservierte Wort Typname vorangestellt ist. Solche generischen Typen an dieser Position werden Vorlagenparameter genannt.
Die folgende Anweisung kann in main() oder in jeder anderen Funktion geschrieben werden:
cout << piUnd die Funktion würde 3 . anzeigen.14. Der Ausdruck pi
Bei der Spezialisierung wird der gewählte Datentyp, z. B. float, in spitzen Klammern hinter die Variable gesetzt. Wenn die Template-Head-Deklaration mehr als einen Template-Parameter enthält, gibt es im Spezialisierungsausdruck eine entsprechende Anzahl von Datentypen in derselben Reihenfolge order.
Bei der Spezialisierung wird ein Typ als Vorlagenargument bezeichnet. Verwechseln Sie dies nicht mit dem Funktionsargument für den Funktionsaufruf.
Standardtyp
Wenn bei der Spezialisierung kein Typ angegeben ist, wird der Standardtyp angenommen. Also aus folgendem Ausdruck:
VorlageU pi = "Liebe";
die Anzeige von:
cout << pi<> << '\n';
ist „Liebe“ für den ständigen Zeiger auf char. Beachten Sie in der Deklaration, dass U = const char*. Die spitzen Klammern sind bei der Spezialisierung leer (kein Typ angegeben); der tatsächliche Typ wird als const-Zeiger auf char betrachtet, den Standardtyp. Wenn bei der Spezialisierung ein anderer Typ benötigt wird, wird der Typname in die spitzen Klammern geschrieben. Wenn der Standardtyp bei der Spezialisierung gewünscht wird, ist die Wiederholung des Typs in den spitzen Klammern optional, d.e., die spitzen Klammern können leer bleiben.
Hinweis: Der Standardtyp kann bei der Spezialisierung immer noch geändert werden, indem ein anderer Typ verwendet wird.
strukturieren
Das folgende Beispiel zeigt, wie ein Vorlagenparameter mit einer Struktur verwendet werden kann:
VorlageTJohn = 11;
TPeter = 12;
T Maria = 13;
T Freude = 14;
;
Dies sind die Altersstufen der Schüler in einer Klasse (Klasse). Die erste Zeile ist die Vorlagendeklaration. Der Körper in geschweiften Klammern ist die eigentliche Definition der Vorlage. Die Altersangaben können in der Funktion main() wie folgt ausgegeben werden:
Altercout << grade7.John << " << grade7.Mary << '\n';
Die Ausgabe ist: 11 13. Die erste Anweisung hier führt die Spezialisierung durch. Beachten Sie, wie es gemacht wurde. Es gibt auch einen Namen für ein Objekt der Struktur: grade7. Die zweite Anweisung hat gewöhnliche Strukturobjektausdrücke. Eine Struktur ist wie eine Klasse. Ages ist hier wie ein Klassenname, während grade7 ein Objekt der Klasse (struct) ist.
Wenn einige Altersangaben Ganzzahlen und andere Gleitkommazahlen sind, benötigt die Struktur zwei generische Parameter wie folgt:
VorlageTJohn = 11;
U Peter = 12.3;
T Maria = 13;
U Freude = 14.6;
;
Ein relevanter Code für die main()-Funktion lautet wie folgt:
Altercout << grade7.John << " << grade7.Peter << '\n';
Die Ausgabe ist: 11 12.3. Bei der Spezialisierung muss die Reihenfolge der Typen (Argumente) der Reihenfolge der generischen Typen in der Deklaration entsprechen.
Die Vorlagendeklaration kann wie folgt von der Definition getrennt werden:
VorlageT. John;
U Peter;
T Maria;
U Freude;
;
Alter
Das erste Codesegment ist eine reine Deklaration einer Vorlage (es gibt keine Zuordnungen). Das zweite Codesegment, das nur eine Aussage ist, ist die Definition des Identifikators, grade7. Die linke Seite ist die Deklaration des Bezeichners, grade7. Auf der rechten Seite befindet sich die Initialisierungsliste, die den Strukturmitgliedern entsprechende Werte zuweist. Das zweite Segment (Anweisung) kann in der main()-Funktion geschrieben werden, während das erste Segment außerhalb der main()-Funktion bleibt.
Nicht-Typ
Beispiele für Nicht-Datentypen sind int, Zeiger auf Objekt, Zeiger auf Funktion und Auto-Typen. Es gibt andere Nicht-Typen, auf die dieser Artikel nicht eingeht. Ein Nicht-Typ ist wie ein unvollständiger Typ, dessen Wert später angegeben wird und nicht geändert werden kann. Als Parameter beginnt er mit einem bestimmten Nicht-Typ, gefolgt von einem Bezeichner. Der Wert des Bezeichners wird später bei der Spezialisierung angegeben und kann nicht mehr geändert werden (wie eine Konstante, deren Wert später angegeben wird). Das folgende Programm veranschaulicht dies:
#einschließenVerwenden von Namespace-Std;
Vorlage
T John = N;
U Peter = 12.3;
T Maria = N;
U Freude = 14.6;
;
int main()
Alter
cout << grade7.John << " << grade7.Joy << '\n';
0 zurückgeben;
Bei der Spezialisierung dient der erste Typ, int, in den spitzen Klammern eher der Formalität, um sicherzustellen, dass die Anzahl und Reihenfolge der Parameter der Anzahl und Reihenfolge der Typen (Argumente) entspricht. Der Wert von N wurde bei der Spezialisierung angegeben. Die Ausgabe ist: 11 14.6.
Teilspezialisierung
Nehmen wir an, eine Vorlage hat vier generische Typen und unter den vier Typen sind zwei Standardtypen erforderlich. Dies kann mit dem partiellen Spezialisierungskonstrukt erreicht werden, das den Zuweisungsoperator nicht verwendet. Das partielle Spezialisierungskonstrukt gibt also einer Untermenge von generischen Typen Standardwerte. Im Schema der partiellen Spezialisierung werden jedoch eine Basisklasse (struct) und eine partielle Spezialisierungsklasse (struct) benötigt. Das folgende Programm veranschaulicht dies für einen generischen Typ von zwei generischen Typen:
#einschließenVerwenden von Namespace-Std;
//Basis-Template-Klasse
Vorlage
struct Ages
;
//teilweise Spezialisierung
Vorlage
struct Ages
T1 Johannes = 11;
Schwimmer Peter = 12.3;
T1 Maria = 13;
schweben Freude = 14.6;
;
int main()
Alter
cout << grade7.John << " << grade7.Joy << '\n';
0 zurückgeben;
Identifizieren Sie die Basisklassendeklaration und ihre partielle Klassendefinition. Die Template-Head-Deklaration der Basisklasse hat alle notwendigen generischen Parameter. Die template-head-Deklaration der partiellen Spezialisierungsklasse hat nur den generischen Typ. Es gibt einen zusätzlichen Satz spitzer Klammern, die im Schema verwendet werden, das direkt nach dem Namen der Klasse in der partiellen Spezialisierungsdefinition steht. Es ist das, was die Teilspezialisierung tatsächlich bewirkt. Es hat den Standardtyp und den Nicht-Standardtyp, in der Reihenfolge, die in der Basisklasse geschrieben ist. Beachten Sie, dass dem Standardtyp in der Funktion main() immer noch ein anderer Typ zugewiesen werden kann.
Der relevante Code in der main()-Funktion kann wie folgt aussehen:
Altercout << grade7.John << " << grade7.Joy << '\n';
Die Ausgabe ist: 11 14.6.
Vorlagen-Parameterpaket
Ein Parameterpaket ist ein Vorlagenparameter, der null oder mehr generische Vorlagentypen für die entsprechenden Datentypen akzeptiert. Der Parameterpaketparameter beginnt mit dem reservierten Wort typename oder class. Darauf folgen drei Punkte und dann die Kennung für das Paket. Das folgende Programm veranschaulicht, wie ein Vorlagenparameterpaket mit einer Struktur verwendet werden kann:
#einschließenVerwenden von Namespace-Std;
Vorlage
int John = 11;
Schwimmer Peter = 12.3;
int Mary = 13;
schweben Freude = 14.6;
;
int main()
Alter
cout << gradeB.John << " << gradeB.Mary << '\n';
Alter
cout << gradeC.Peter << " << gradeC.Joy << '\n';
Alter
cout << gradeD.John << " << gradeD.Joy << '\n';
Alter<> GradA; //wie Standard
cout << gradeA.John << " << gradeA.Joy << '\n';
0 zurückgeben;
Die Ausgabe ist:
11 1312.3 14.6
11 14.6
11 14.6
Funktionsvorlagen
Die oben genannten Template-Features gelten in ähnlicher Weise für Funktions-Templates. Das folgende Programm zeigt eine Funktion mit zwei generischen Vorlagenparametern und drei Argumenten:
#einschließenVerwenden von Namespace-Std;
Vorlage
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
int main()
func(12, '$', "500");
0 zurückgeben;
Die Ausgabe ist wie folgt:
Es gibt 12 Bücher im Wert von 500 $ im Laden.
Trennung vom Prototyp
Die Funktionsdefinition kann von ihrem Prototyp getrennt werden, wie das folgende Programm zeigt:
#einschließenVerwenden von Namespace-Std;
Vorlage
Vorlage
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
int main()
func(12, '$', "500");
0 zurückgeben;
Hinweis: Die Deklaration der Funktionsvorlage kann nicht in der main()-Funktion oder in einer anderen Funktion vorkommen.
Überlastung
Das Überladen der gleichen Funktion kann mit unterschiedlichen Template-Head-Deklarationen erfolgen. Das folgende Programm veranschaulicht dies:
#einschließenVerwenden von Namespace-Std;
Vorlage
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
Vorlage
cout << "There are " << no << " books worth $" << str << " in the store." << '\n';
int main()
func(12, '$', "500");
func(12, "500");
0 zurückgeben;
Die Ausgabe ist:
Es gibt 12 Bücher im Wert von 500 $ im Laden.
Es gibt 12 Bücher im Wert von 500 $ im Laden.
Klassenvorlagen
Die Funktionen der oben genannten Vorlagen gelten in ähnlicher Weise für Klassenvorlagen. Das folgende Programm ist die Deklaration, Definition und Verwendung einer einfachen Klasse:
#einschließenVerwenden von Namespace-Std;
Klasse TheCla
Öffentlichkeit:
int-Zahl;
statisches Zeichen ch;
void func (char cha, const char *str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
statischer Leerspaß (char ch)
if (ch == 'a')
cout << "Official static member function" << '\n';
;
int main()
TheCla obj;
obj.Anzahl = 12;
obj.func('$', "500");
0 zurückgeben;
Die Ausgabe ist wie folgt:
Es gibt 12 Bücher im Wert von 500 $ im Laden.
Das folgende Programm ist das obige Programm mit einer Template-Head-Deklaration:
#einschließenVerwenden von Namespace-Std;
Vorlage
Öffentlichkeit:
T-Zahl;
statische U ch;
void func (U cha, const char *str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
statischer Leerspaß (U ch)
if (ch == 'a')
cout << "Official static member function" << '\n';
;
int main()
TheCla
obj.Anzahl = 12;
obj.func('$', "500");
0 zurückgeben;
Anstelle des Worttypnamens in der Vorlagenparameterliste kann die Wortklasse verwendet werden. Beachten Sie die Spezialisierung in der Deklaration des Objekts. Die Ausgabe ist immer noch dieselbe:
Es gibt 12 Bücher im Wert von 500 $ im Laden.
Trennerklärung
Die Klassenvorlagendeklaration kann wie folgt vom Klassencode getrennt werden:
VorlageVorlage
Öffentlichkeit:
T-Zahl;
statische U ch;
void func (U cha, const char *str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
statischer Leerspaß (U ch)
if (ch == 'a')
cout << "Official static member function" << '\n';
;
Umgang mit statischen Mitgliedern
Das folgende Programm zeigt, wie Sie auf einen statischen Datenmember und eine statische Memberfunktion zugreifen:
#einschließenVerwenden von Namespace-Std;
Vorlage
Öffentlichkeit:
T-Zahl;
statische U ch;
void func (U cha, const char *str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
statischer Leerspaß (U cha)
if (ch == 'a')
cout << "Official static member function" << cha << '\n';
;
Vorlage
int main()
TheCla
0 zurückgeben;
Das Zuweisen eines Werts zu einem statischen Datenmember ist eine Deklaration und kann nicht in main() enthalten sein. Beachten Sie die Verwendung und Position der generischen Typen und des generischen Datentyps in der Zuweisungsanweisung. Beachten Sie außerdem, dass die statische Datenmemberfunktion in main() mit den tatsächlichen Vorlagendatentypen aufgerufen wurde. Die Ausgabe ist die folgende:
Offizielle statische Memberfunktion.
Kompilieren
Die Deklaration (Header) und die Definition einer Vorlage müssen in einer Datei vorliegen. Das heißt, sie müssen sich in derselben Übersetzungseinheit befinden.
Fazit
C++-Templates machen einen Algorithmus unabhängig von der Art der verwendeten Daten. Die Entitäten von Variable, Funktion, Struktur und Klasse können Vorlagen haben, die Deklaration und Definition beinhalten. Das Erstellen einer Vorlage beinhaltet auch eine Spezialisierung, wenn ein generischer Typ einen tatsächlichen Typ annimmt. Die Deklaration und die Definition einer Vorlage müssen sich in einer Übersetzungseinheit befinden.