C++

C++-sjablonen gebruiken

C++-sjablonen gebruiken

Invoering

In de basisprogrammering van C++ is het gegevenstype e.g., int of char, moet worden aangegeven in een verklaring of een definitie. Een waarde zoals 4 of 22 of -5 is een int. Een waarde zoals 'A' of 'b' of 'c' is een char. Met het sjabloonmechanisme kan de programmeur een generiek type gebruiken voor een reeks werkelijke typen actual. De programmeur kan bijvoorbeeld besluiten om de identifier T te gebruiken voor int of char. Het is mogelijk dat een C++-algoritme meer dan één generiek type heeft. Met bijvoorbeeld T voor de int of char, kan U staan ​​voor het type float of pointer. Een klasse, zoals de tekenreeks- of vectorklasse, is als een gegevenstype en de geïnstantieerde objecten zijn als waarden van het gegevenstype, wat de opgegeven klasse is. Het sjabloonmechanisme stelt de programmeur dus ook in staat om een ​​generieke typeaanduiding te gebruiken voor een reeks klassen.

Een C++-sjabloon creëert een algoritme dat onafhankelijk is van het type gegevens dat wordt gebruikt. Dus hetzelfde algoritme, met veel voorkomen van hetzelfde type, kan verschillende typen gebruiken bij verschillende uitvoeringen. De entiteiten van variabele, functie, struct en klasse kunnen sjablonen hebben. In dit artikel wordt uitgelegd hoe u sjablonen declareert, sjablonen definieert en hoe u ze toepast in C++. U moet al kennis hebben van de bovengenoemde entiteiten om de onderwerpen in dit artikel te begrijpen.

Types

scalair

De scalaire typen zijn void, bool, char, int, float en pointer.

Klassen als typen

Een bepaalde klasse kan worden beschouwd als een type en zijn objecten als mogelijke waarden.

Een generiek type vertegenwoordigt een reeks scalaire typen. De lijst met scalaire typen is uitgebreid. Het int-type heeft bijvoorbeeld andere verwante typen, zoals short int, long int, etc. Een generiek type kan ook een reeks klassen vertegenwoordigen.

Variabele

Een voorbeeld van een modelverklaring en definitie is als volgt:

sjabloon
Tpi = 3.14;

Houd er rekening mee dat dit soort instructies niet kunnen verschijnen in de functie main() of in een blokbereik. De eerste regel is de template-head-declaratie, met de door de programmeur gekozen generieke typenaam, T. De volgende regel is de definitie van de identifier, pi, die van het generieke type is, T. Precisie, of de T nu een int of een float of een ander type is, kan worden gedaan in de C++ main()-functie (of een andere functie). Een dergelijke precisie wordt gedaan met de variabele pi, en niet met T.

De eerste regel is de template-head-declaratie. Deze verklaring begint met het gereserveerde woord, de sjabloon en vervolgens de open en gesloten punthaken. Binnen de punthaken is er ten minste één generieke typeaanduiding, zoals T, hierboven. Er kan meer dan één generieke type-ID zijn, elk voorafgegaan door het gereserveerde woord typenaam type. Dergelijke generieke typen op die positie worden sjabloonparameters genoemd.

De volgende instructie kan worden geschreven in main() of in een andere functie:

cout << pi << '\n';

En de functie zou 3 . weergeven.14. de uitdrukking pi bepaalt het exacte type T voor de variabele pi. Specialisatie bepaalt het specifieke gegevenstype voor de sjabloonparameter. Instantiatie is het interne C++-proces voor het maken van het specifieke type, zoals float, in dit geval. Verwar niet tussen het instantiëren van een sjabloonparameter en het instantiëren van een klasse. In het sjabloononderwerp kunnen veel gegevenstypen één generieke typenaam hebben, terwijl veel klassen één generieke klassenaam kunnen hebben. De generieke klassenaam voor klassen wordt echter eenvoudigweg een klasse genoemd en niet een klassenaam. Een waarde is ook voor een gegevenstype, zoals de int, zoals een geïnstantieerd object is voor een klasse, zoals de klasse String.

Bij specialisatie wordt het gekozen datatype, zoals float, tussen punthaken geplaatst na de variabele. Als er meer dan één sjabloonparameter in de sjabloonkopdeclaratie is, is er een overeenkomstig aantal gegevenstypen in dezelfde volgorde in de specialisatie-expressie.

Bij specialisatie staat een type bekend als een sjabloonargument. Verwar dit niet met het functieargument voor functieaanroep.

Standaardtype

Als er geen type is opgegeven bij specialisatie, wordt het standaardtype aangenomen. Dus uit de volgende uitdrukking:

sjabloon
U pi = "liefde";
de weergave van:
cout << pi<> << '\n';

is "liefde" voor de constante aanwijzer naar char. Noteer in de verklaring dat U = const char*. De punthaken zijn leeg bij specialisatie (geen type opgegeven); het werkelijke type wordt beschouwd als een const-aanwijzer naar char, het standaardtype. Als er een ander type nodig was bij specialisatie, dan zou de typenaam tussen punthaken worden geschreven. Als het standaardtype bij specialisatie gewenst is, is het herhalen van het type tussen punthaken optioneel, i.e., de punthaken mogen leeg blijven.

Opmerking: het standaardtype kan bij specialisatie nog steeds worden gewijzigd door een ander type te hebben.

structureren

Het volgende voorbeeld laat zien hoe een sjabloonparameter kan worden gebruikt met een struct:

sjabloon struct Ages

T Johannes = 11;
T Peter = 12;
T Maria = 13;
T Vreugde = 14;
;

Dit zijn leeftijden van leerlingen in een leerjaar (klas). De eerste regel is de sjabloondeclaratie. Het lichaam tussen accolades is de eigenlijke definitie van de sjabloon. De leeftijden kunnen worden uitgevoerd in de functie main() met het volgende:

leeftijden cijfer7;
cout << grade7.John << " << grade7.Mary << '\n';

De uitvoer is: 11 13. De eerste verklaring hier voert de specialisatie uit. Let op hoe het is gemaakt. Het geeft ook een naam voor een object van de struct: grade7. De tweede instructie heeft gewone struct-objectexpressies. Een struct is als een klas. Hier is Ages als een klassenaam, terwijl grade7 een object van de klasse is (struct).

Als sommige leeftijden gehele getallen zijn en andere floats, dan heeft de struct twee generieke parameters nodig, als volgt:

sjabloon struct Ages

T Johannes = 11;
U Peter = 12.3;
T Maria = 13;
U Vreugde = 14.6;
;

Een relevante code voor de functie main() is als volgt:

leeftijden cijfer7;
cout << grade7.John << " << grade7.Peter << '\n';

De uitvoer is: 11 12.3. Bij specialisatie moet de volgorde van de typen (argumenten) overeenkomen met de volgorde van de generieke typen in de aangifte.

De modelaangifte kan als volgt van de definitie worden gescheiden:

sjabloon struct Ages

T Jan;
u Peter;
T Maria;
u Vreugde;
;
leeftijden cijfer7 = 11, 12.3, 13, 14.6;

Het eerste codesegment is puur een verklaring van een sjabloon (er zijn geen toewijzingen). Het tweede codesegment, dat slechts een verklaring is, is de definitie van de identifier, grade7. De linkerkant is de verklaring van de identifier, grade7. De rechterkant is de initialisatielijst, die overeenkomstige waarden toewijst aan de structleden. Het tweede segment (statement) kan worden geschreven in de functie main(), terwijl het eerste segment buiten de functie main() blijft.

Niet-type

Voorbeelden van niet-gegevenstypen zijn de int, aanwijzer naar object, aanwijzer naar functie en auto-typen. Er zijn andere niet-typen, die in dit artikel niet worden behandeld. Een niet-type is als een onvolledig type, waarvan de waarde later wordt gegeven en niet kan worden gewijzigd. Als parameter begint het met een bepaald niet-type, gevolgd door een identifier. De waarde van de identifier wordt later gegeven, bij specialisatie, en kan niet opnieuw worden gewijzigd (zoals een constante, waarvan de waarde later wordt gegeven). Het volgende programma illustreert dit:

#include
namespace std; gebruiken;
sjabloon struct Ages

T Jan = N;
U Peter = 12.3;
T Maria = N;
U Vreugde = 14.6;
;
int hoofd()

leeftijden cijfer7;
cout << grade7.John << " << grade7.Joy << '\n';
retourneer 0;

Bij specialisatie is het eerste type, int, tussen punthaken meer voor de formaliteit, om ervoor te zorgen dat het aantal en de volgorde van parameters overeenkomen met het aantal en de volgorde van typen (argumenten). De waarde van N is gegeven bij specialisatie. De uitvoer is: 11 14.6.

Gedeeltelijke specialisatie

Laten we aannemen dat een sjabloon vier generieke typen heeft en dat er van de vier typen twee standaardtypen nodig zijn. Dit kan worden bereikt met behulp van de constructie van gedeeltelijke specialisatie, die geen gebruik maakt van de toewijzingsoperator. De constructie van gedeeltelijke specialisatie geeft dus standaardwaarden aan een subset van generieke typen. In het deelspecialisatieschema zijn echter een basisklasse (struct) en een gedeeltelijke specialisatieklasse (struct) nodig. Het volgende programma illustreert dit voor één generiek type uit twee generieke typen:

#include
namespace std; gebruiken;
//basissjabloonklasse
sjabloon
struct Ages

;
//gedeeltelijke specialisatie
sjabloon
struct Ages

T1 Jan = 11;
drijver Peter = 12.3;
T1 Maria = 13;
drijven Vreugde = 14.6;
;
int hoofd()

leeftijden cijfer7;
cout << grade7.John << " << grade7.Joy << '\n';
retourneer 0;

Identificeer de basisklassedeclaratie en de gedeeltelijke klassendefinitie. De sjabloonkopdeclaratie van de basisklasse heeft alle benodigde generieke parameters. De sjabloonkopdeclaratie van de gedeeltelijke specialisatieklasse heeft alleen het generieke type type. Er is een extra set punthaken gebruikt in het schema dat net achter de naam van de klasse komt in de gedeeltelijke specialisatiedefinitie. Het is wat de gedeeltelijke specialisatie eigenlijk doet. Het heeft het standaardtype en het niet-standaardtype, in de volgorde geschreven in de basisklasse. Merk op dat het standaardtype nog steeds een ander type kan krijgen in de functie main().

De relevante code in de functie main() kan als volgt zijn:

leeftijden cijfer7;
cout << grade7.John << " << grade7.Joy << '\n';

De uitvoer is: 11 14.6.

Sjabloonparameterpakket

Een parameterpakket is een sjabloonparameter die nul of meer generieke sjabloontypen accepteert voor de bijbehorende gegevenstypen. De parameterpakketparameter begint met het gereserveerde woord typenaam of klasse. Dit wordt gevolgd door drie stippen en vervolgens de identifier voor het pakket. Het volgende programma illustreert hoe een sjabloonparameterpakket kan worden gebruikt met een struct:

#include
namespace std; gebruiken;
sjabloon struct Ages

int Johannes = 11;
drijver Peter = 12.3;
int Maria = 13;
drijven Vreugde = 14.6;
;
int hoofd()

leeftijden graad B;
cout << gradeB.John << " << gradeB.Mary << '\n';
leeftijden graadC;
cout << gradeC.Peter << " << gradeC.Joy << '\n';
leeftijden cijferD;
cout << gradeD.John << " << gradeD.Joy << '\n';
Leeftijden<> klasseA; //zoals standaard
cout << gradeA.John << " << gradeA.Joy << '\n';
retourneer 0;

De uitvoer is:

11 13
12.3 14.6
11 14.6
11 14.6

Functiesjablonen

De hierboven genoemde sjabloonfuncties zijn op dezelfde manier van toepassing op functiesjablonen. Het volgende programma toont een functie met twee generieke sjabloonparameters en drie argumenten:

#include
namespace std; gebruiken;
sjabloon void func (T no, U cha, const char *str )

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

int hoofd()

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

De uitvoer is als volgt:

Er zijn 12 boeken ter waarde van $500 in de winkel.

Scheiding van prototype

De functiedefinitie kan worden gescheiden van het prototype, zoals het volgende programma laat zien:

#include
namespace std; gebruiken;
sjabloon void func (T no, U cha, const char *str );
sjabloon void func (T no, U cha, const char *str )

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

int hoofd()

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

Opmerking: de functiesjabloondeclaratie kan niet voorkomen in de functie main() of in een andere functie.

overbelasting

Overbelasting van dezelfde functie kan plaatsvinden met verschillende template-head declaraties. Het volgende programma illustreert dit:

#include
namespace std; gebruiken;
sjabloon void func (T no, U cha, const char *str )

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

sjabloon void func (T nee, const char *str )

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

int hoofd()

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

De uitvoer is:

Er zijn 12 boeken ter waarde van $500 in de winkel.

Er zijn 12 boeken ter waarde van $500 in de winkel.

Klassjablonen

De kenmerken van de hierboven genoemde sjablonen zijn op dezelfde manier van toepassing op klassjablonen. Het volgende programma is de verklaring, definitie en gebruik van een eenvoudige klasse:

#include
namespace std; gebruiken;
klasse TheCla

openbaar:
int. aantal;
statisch teken;
void func (char cha, const char *str)

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

statische leegte plezier (char ch)

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

;
int hoofd()

DeCla obj;
obj.aantal = 12;
obj.func('$', "500");
retourneer 0;

De uitvoer is als volgt:

Er zijn 12 boeken ter waarde van $500 in de winkel.

Het volgende programma is het bovenstaande programma met een template-head declaratie:

#include
namespace std; gebruiken;
sjabloon klasse TheCla

openbaar:
T aantal;
statisch Uch;
void func (U cha, const char *str)

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

statische leegte plezier (U ch)

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

;
int hoofd()

De Cla obj;
obj.aantal = 12;
obj.func('$', "500");
retourneer 0;

In plaats van het woord typenaam in de sjabloonparameterlijst, kan de woordklasse worden gebruikt. Let op de specialisatie in de aangifte van het object. De output is nog steeds hetzelfde:

Er zijn 12 boeken ter waarde van $500 in de winkel.

Scheidingsverklaring

De declaratie van het klassensjabloon kan als volgt worden gescheiden van de klassencode:

sjabloon klasse TheCla;
sjabloon klasse TheCla

openbaar:
T aantal;
statisch Uch;
void func (U cha, const char *str)

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

statische leegte plezier (U ch)

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

;

Omgaan met statische leden

Het volgende programma laat zien hoe u toegang krijgt tot een statisch gegevenslid en een statische lidfunctie:

#include
namespace std; gebruiken;
sjabloon klasse TheCla

openbaar:
T aantal;
statisch Uch;
void func (U cha, const char *str)

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

statische leegte plezier (U cha)

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

;
sjabloon U TheCla::ch = 'een';
int hoofd()

De Cla::pret('.');
retourneer 0;

Het toewijzen van een waarde aan een statisch gegevenslid is een declaratie en kan niet in main() zijn. Let op het gebruik en de posities van de generieke typen en het generieke gegevenstype in de toewijzingsinstructie. Houd er bovendien rekening mee dat de functie voor het lid van statische gegevens is aangeroepen in main(), met de daadwerkelijke sjabloongegevenstypen. De uitvoer is de volgende:

Officiële statische ledenfunctie.

Compileren

De aangifte (header) en de definitie van een sjabloon moeten in één bestand staan. Dat wil zeggen, ze moeten zich in dezelfde vertaaleenheid bevinden.

Conclusie

C++-sjablonen maken een algoritme onafhankelijk van het type gegevens dat wordt gebruikt. De entiteiten van variabele, functie, struct en klasse kunnen sjablonen hebben, waarbij declaratie en definitie betrokken zijn. Het maken van een sjabloon omvat ook specialisatie, dat is wanneer een generiek type een echt type krijgt actual. De aangifte en de definitie van een sjabloon moeten beide in één vertaaleenheid staan.

Strijd om Wesnoth 1.13.6 Ontwikkeling vrijgegeven
Strijd om Wesnoth 1.13.6 die vorige maand werd uitgebracht, is de zesde ontwikkelingsrelease in de 1.13.x-serie en het levert een aantal verbeteringen...
Hoe League Of Legends op Ubuntu 14 te installeren.04
Als je fan bent van League of Legends, dan is dit een kans voor jou om League of Legends te testen. Merk op dat LOL wordt ondersteund op PlayOnLinux a...
Installeer de nieuwste OpenRA Strategy Game op Ubuntu Linux
OpenRA is een Libre/Free Real Time Strategy-game-engine die de vroege Westwood-games nabootst, zoals de klassieke Command & Conquer: Red Alert. Gedist...