C ++

Cum se utilizează șabloanele C ++

Cum se utilizează șabloanele C ++

Introducere

În programarea de bază C ++, tipul de date, e.g., int sau char, trebuie indicat într-o declarație sau o definiție. O valoare precum 4 sau 22 sau -5 este o valoare int. O valoare precum „A” sau „b” sau „c” este un caracter. Mecanismul șablon permite programatorului să utilizeze un tip generic pentru un set de tipuri reale. De exemplu, programatorul poate decide să utilizeze identificatorul T pentru int sau char. Este posibil ca un algoritm C ++ să aibă mai mult de un tip generic. Cu, să zicem, T pentru int sau char, U poate reprezenta tipul float sau pointer. O clasă, cum ar fi șirul sau clasa vectorială, este ca un tip de date, iar obiectele instanțiate sunt ca valori ale tipului de date, care este clasa specificată. Deci, mecanismul șablon permite, de asemenea, programatorului să utilizeze un identificator de tip generic pentru un set de clase.

Un șablon C ++ creează un algoritm independent de tipul de date utilizate. Deci, același algoritm, cu multe apariții de același tip, poate utiliza diferite tipuri la diferite execuții. Entitățile variabilei, funcției, structurii și clasei pot avea șabloane. Acest articol explică cum să declarați șabloane, cum să definiți șabloane și cum să le aplicați în C++. Ar trebui să aveți deja cunoștințe despre entitățile menționate anterior pentru a înțelege subiectele tratate în acest articol.

Tipuri

Scalar

Tipurile scalare sunt void, bool, char, int, float și pointer.

Clasele ca tipuri

O anumită clasă poate fi considerată ca un tip și obiectele sale ca valori posibile.

Un tip generic reprezintă un set de tipuri scalare. Lista tipurilor de scalare este extinsă. Tipul int, de exemplu, are alte tipuri conexe, precum int scurt, int lung etc. Un tip generic poate reprezenta, de asemenea, un set de clase.

Variabil

Un exemplu de declarație și definiție șablon este după cum urmează:

șablon
T pi = 3.14;

Înainte de a continua, rețineți că acest tip de declarație nu poate apărea în funcția main () sau în orice domeniu de bloc. Prima linie este declarația cap-șablon, cu numele de tip generic ales de programator, T. Următoarea linie este definiția identificatorului, pi, care este de tip generic, T. Precizia, indiferent dacă T este un int sau un float sau un alt tip, se poate face în funcția C ++ main () (sau în altă funcție). O astfel de precizie se va face cu variabila pi, și nu cu T.

Prima linie este declarația cap-șablon. Această declarație începe cu cuvântul rezervat, șablonul și apoi parantezele unghiulare deschise și închise. În parantezele unghiulare, există cel puțin un identificator de tip generic, cum ar fi T, de mai sus. Poate exista mai mult de un identificator de tip generic, fiecare fiind precedat de cuvântul rezervat, typename. Astfel de tipuri generice în acea poziție se numesc parametri șablon.

Următoarea afirmație poate fi scrisă în main () sau în orice altă funcție:

cout << pi << '\n';

Iar funcția ar afișa 3.14. Expresia pi decide tipul exact de T pentru variabila pi. Specializarea decide tipul de date particular pentru parametrul șablon. Instanțierea este procesul intern C ++ de creare a unui anumit tip, cum ar fi float, în acest caz. Nu confundați între instanțierea unui parametru șablon și instanțierea unei clase. În subiectul șablon, multe tipuri de date pot avea un singur nume de tip generic, în timp ce multe clase pot avea un singur nume de clasă generic. Cu toate acestea, numele generic de clasă pentru clase este pur și simplu denumit clasă și nu ca nume de clasă. De asemenea, o valoare este pentru un tip de date, cum ar fi int, deoarece un obiect instanțiat este pentru o clasă, cum ar fi clasa String.

La specializare, tipul de date ales, cum ar fi float, este plasat în paranteze unghiulare după variabilă. Dacă există mai mult de un parametru de șablon în declarația cap-șablon, va exista un număr corespunzător de tipuri de date în aceeași ordine în expresia de specializare.

La specializare, un tip este cunoscut sub numele de argument șablon. Nu confundați între acesta și argumentul funcției pentru apelul funcțional.

Tip implicit

Dacă nu este dat niciun tip la specializare, se presupune tipul implicit. Deci, din următoarea expresie:

șablon
U pi = "dragoste";
afișajul de la:
cout << pi<> << '\n';

este „dragoste” pentru indicatorul constant către char. Rețineți în declarație că U = const char *. Parantezele unghiulare vor fi goale la specializare (nu se dă niciun tip); tipul real este considerat un pointer const la char, tipul implicit. Dacă ar fi nevoie de un alt tip la specializare, atunci numele tipului ar fi scris între paranteze. Când tipul implicit este dorit la specializare, repetarea tipului între paranteze este opțională, i.e., parantezele unghiulare pot fi lăsate goale.

Notă: tipul implicit poate fi schimbat în continuare la specializare, având un alt tip.

struct

Următorul exemplu arată cum poate fi utilizat un parametru șablon cu o structură:

șablon struct Ages

T John = 11;
T Petru = 12;
T Maria = 13;
T Bucuria = 14;
;

Acestea sunt vârste ale elevilor dintr-o clasă (clasă). Prima linie este declarația șablon. Corpul din paranteză este definiția reală a șablonului. Vârstele pot fi transmise în funcția main () cu următoarele:

Vârste Gradul 7;
cout << grade7.John << " << grade7.Mary << '\n';

Ieșirea este: 11 13. Prima afirmație de aici efectuează specializarea. Rețineți cum a fost realizat. De asemenea, dă un nume pentru un obiect al struct: grade7. A doua afirmație are expresii obișnuite struct struct. O structură este ca o clasă. Aici, Ages este ca un nume de clasă, în timp ce nota 7 este un obiect al clasei (struct).

Dacă unele vârste sunt întregi și altele sunt flotante, structura are nevoie de doi parametri generici, după cum urmează:

șablon struct Ages

T John = 11;
U Petru = 12.3;
T Maria = 13;
U Bucuria = 14.6;
;

Un cod relevant pentru funcția main () este după cum urmează:

Vârste Gradul 7;
cout << grade7.John << " << grade7.Peter << '\n';

Ieșirea este: 11 12.3. La specializare, ordinea tipurilor (argumentelor) trebuie să corespundă ordinii tipurilor generice din declarație.

Declarația șablon poate fi separată de definiție, după cum urmează:

șablon struct Ages

T John;
U Peter;
T Maria;
U Bucuria;
;
Vârste nota 7 = 11, 12.3, 13, 14.6;

Primul segment de cod este pur și simplu o declarație a unui șablon (nu există atribuții). Al doilea segment de cod, care este doar o afirmație, este definiția identificatorului, gradul 7. Partea stângă este declarația identificatorului, gradul 7. Partea dreaptă este lista inițializatorului, care atribuie valorile corespunzătoare membrilor struct. Al doilea segment (declarație) poate fi scris în funcția main (), în timp ce primul segment rămâne în afara funcției main ().

Non-Type

Exemple de tipuri non-date includ int, pointer către obiect, pointer către funcție și tipuri automate. Există alte non-tipuri, pe care acest articol nu le abordează. Un non-tip este ca un tip incomplet, a cărui valoare este dată ulterior și nu poate fi modificată. Ca parametru, începe cu un anumit tip, urmat de un identificator. Valoarea identificatorului este dată mai târziu, la specializare, și nu poate fi schimbată din nou (ca o constantă, a cărei valoare este dată mai târziu). Următorul program ilustrează acest lucru:

#include
folosind spațiul de nume std;
șablon struct Ages

T John = N;
U Petru = 12.3;
T Maria = N;
U Bucuria = 14.6;
;
int main ()

Vârste Gradul 7;
cout << grade7.John << " << grade7.Joy << '\n';
retur 0;

La specializare, primul tip, int, între paranteze unghiulare este mai mult pentru formalitate, pentru a vă asigura că numărul și ordinea parametrilor corespund numărului și ordinii tipurilor (argumente). Valoarea lui N a fost dată la specializare. Ieșirea este: 11 14.6.

Specializare parțială

Să presupunem că un șablon are patru tipuri generice și că, dintre cele patru tipuri, este nevoie de două tipuri implicite. Acest lucru poate fi realizat folosind constructul de specializare parțială, care nu angajează operatorul de atribuire. Deci, constructul de specializare parțială oferă valori implicite unui subset de tipuri generice. Cu toate acestea, în schema de specializare parțială, sunt necesare o clasă de bază (struct) și o clasă de specializare parțială (struct). Următorul program ilustrează acest lucru pentru un tip generic din două tipuri generice:

#include
folosind spațiul de nume std;
// clasa șablon de bază
șablon
struct Ages

;
// specializare parțială
șablon
struct Ages

T1 Ioan = 11;
pluteste Petru = 12.3;
T1 Maria = 13;
float Joy = 14.6;
;
int main ()

Vârste Gradul 7;
cout << grade7.John << " << grade7.Joy << '\n';
retur 0;

Identificați declarația clasei de bază și definiția ei parțială a clasei. Declarația cap-șablon a clasei de bază are toți parametrii generici necesari. Declarația cap-șablon a clasei de specializare parțială are doar tipul generic. Există un set suplimentar de paranteze unghiulare utilizate în schemă, care vine imediat după numele clasei în definiția de specializare parțială. Este ceea ce face de fapt specializarea parțială. Are tipul implicit și tipul non-implicit, în ordinea scrisă în clasa de bază. Rețineți că tipului implicit i se poate da încă un tip diferit în funcția main ().

Codul relevant din funcția main () poate fi după cum urmează:

Vârste Gradul 7;
cout << grade7.John << " << grade7.Joy << '\n';

Ieșirea este: 11 14.6.

Pachet de parametri șablon

Un pachet de parametri este un parametru șablon care acceptă zero sau mai multe tipuri generice de șabloane pentru tipurile de date corespunzătoare. Parametrul pachetului parametru începe cu cuvântul rezervat typename sau clasă. Acesta este urmat de trei puncte și apoi de identificatorul pachetului. Următorul program ilustrează modul în care un pachet de parametri șablon poate fi utilizat cu o structură:

#include
folosind spațiul de nume std;
șablon struct Ages

int Ioan = 11;
plutitor Petru = 12.3;
int Maria = 13;
float Joy = 14.6;
;
int main ()

Vârste gradul B;
cout << gradeB.John << " << gradeB.Mary << '\n';
Vârste gradul C;
cout << gradeC.Peter << " << gradeC.Joy << '\n';
Vârste gradul D;
cout << gradeD.John << " << gradeD.Joy << '\n';
Vârste <> gradA; // ca implicit
cout << gradeA.John << " << gradeA.Joy << '\n';
retur 0;

Ieșirea este:

11 13
12.3 14.6
11 14.6
11 14.6

Șabloane de funcții

Funcțiile șablonului menționate mai sus se aplică în mod similar cu șabloanele de funcții. Următorul program prezintă o funcție cu doi parametri șablon generici și trei argumente:

#include
folosind spațiul de nume std;
șablon void func (T no, U cha, const char * str)

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

int main ()

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

Ieșirea este după cum urmează:

Există 12 cărți în valoare de 500 USD în magazin.

Separarea de prototip

Definiția funcției poate fi separată de prototipul său, după cum arată următorul program:

#include
folosind spațiul de nume std;
șablon void func (T no, U cha, const char * str);
șablon void func (T no, U cha, const char * str)

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

int main ()

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

Notă: Declarația șablonului de funcție nu poate apărea în funcția main () sau în orice altă funcție.

Suprasolicitare

Supraîncărcarea aceleiași funcții poate avea loc cu declarații diferite șablon-cap. Următorul program ilustrează acest lucru:

#include
folosind spațiul de nume std;
șablon void func (T no, U cha, const char * str)

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

șablon void func (T nu, const char * str)

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

int main ()

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

Ieșirea este:

Există 12 cărți în valoare de 500 USD în magazin.

Există 12 cărți în valoare de 500 USD în magazin.

Șabloane de clasă

Caracteristicile șabloanelor menționate mai sus se aplică în mod similar cu șabloanele de clasă. Următorul program este declarația, definiția și utilizarea unei clase simple:

#include
folosind spațiul de nume std;
clasa TheCla

public:
int num;
statice char ch;
void func (char cha, const char * str)

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

distracție de vid static (char ch)

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

;
int main ()

TheCla obj;
obiect.num = 12;
obiect.func ('$', "500");
retur 0;

Ieșirea este după cum urmează:

Există 12 cărți în valoare de 500 USD în magazin.

Următorul program este programul de mai sus, cu o declarație cap-șablon:

#include
folosind spațiul de nume std;
șablon clasa TheCla

public:
T num;
static U ch;
void func (U cha, const char * str)

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

distracție de vid static (U ch)

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

;
int main ()

TheCla obj;
obiect.num = 12;
obiect.func ('$', "500");
retur 0;

În loc de cuvântul typename din lista de parametri șablon, se poate folosi clasa de cuvinte. Rețineți specializarea în declarația obiectului. Ieșirea este în continuare aceeași:

Există 12 cărți în valoare de 500 USD în magazin.

Declarație de separare

Declarația șablonului clasei poate fi separată de codul clasei, după cum urmează:

șablon clasa TheCla;
șablon clasa TheCla

public:
T num;
static U ch;
void func (U cha, const char * str)

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

distracție de vid static (U ch)

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

;

Tratarea membrilor statici

Următorul program arată cum să accesați un membru de date statice și o funcție de membru static:

#include
folosind spațiul de nume std;
șablon clasa TheCla

public:
T num;
static U ch;
void func (U cha, const char * str)

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

distracție de vid static (U cha)

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

;
șablon U TheCla:: ch = 'a';
int main ()

TheCla::distracţie('.');
retur 0;

Atribuirea unei valori unui membru de date statice este o declarație și nu poate fi în main (). Rețineți utilizarea și pozițiile tipurilor generice și tipul generic de date în declarația de atribuire. În plus, rețineți că funcția membru static de date a fost apelată în main (), cu tipurile de date șablon reale. Ieșirea este următoarea:

Funcția oficială de membru static.

Compilare

Declarația (antetul) și definiția unui șablon trebuie să fie într-un singur fișier. Adică trebuie să se afle în aceeași unitate de traducere.

Concluzie

Șabloanele C ++ fac un algoritm independent de tipul de date utilizate. Entitățile variabilei, funcției, structurii și clasei pot avea șabloane, care implică declarație și definire. Crearea unui șablon implică, de asemenea, specializarea, care este atunci când un tip generic ia un tip real. Declarația și definiția unui șablon trebuie să fie ambele într-o singură unitate de traducere.

Cum se arată FPS Counter în jocurile Linux
Jocurile cu Linux au primit un impuls major când Valve a anunțat suportul Linux pentru clientul Steam și jocurile acestora în 2012. De atunci, multe j...
How to download and Play Sid Meier's Civilization VI on Linux
Introduction to the game Civilization 6 is a modern take on the classic concept introduced in the series of the Age of Empires games. The idea was fai...
How to Install and Play Doom on Linux
Introduction to Doom The Doom Series originated in the 90s after the release of the original Doom. It was an instant hit and from that time onwards th...