C ++

Как да използвам шаблони на C ++

Как да използвам шаблони на C ++

Въведение

В основното програмиране на C ++ типът данни, напр.ж., int или char, трябва да бъдат посочени в декларация или дефиниция. Стойност като 4 или 22 или -5 е int. Стойност като „A“ или „b“ или „c“ е знак. Механизмът на шаблона позволява на програмиста да използва родов тип за набор от действителни типове. Например програмистът може да реши да използва идентификатора T за int или char. Възможно е алгоритъмът C ++ да има повече от един общ тип. С, да речем, T за int или char, U може да означава тип float или указател. Клас, като низ или векторен клас, е като тип данни, а инстанцираните обекти са като стойности на типа данни, който е посоченият клас. И така, механизмът на шаблона също така позволява на програмиста да използва родов идентификатор на тип за набор от класове.

Шаблонът C ++ създава алгоритъм, независим от типа на използваните данни. И така, един и същ алгоритъм, с много повторения от един и същи тип, може да използва различни типове при различни изпълнения. Обектите на променлива, функция, структура и клас могат да имат шаблони. Тази статия обяснява как да декларирате шаблони, как да дефинирате шаблони и как да ги приложите в C++. Вече трябва да имате познания за гореспоменатите обекти, за да разберете темите, обхванати в тази статия.

Видове

Скалар

Скаларните типове са void, bool, char, int, float и pointer.

Класове като типове

Даден клас може да се разглежда като тип и неговите обекти като възможни стойности.

Общият тип представлява набор от скаларни типове. Списъкът на скаларните типове е обширен. Например типът int има други свързани типове, като например кратко int, дълго int и т.н. Общият тип може също да представлява набор от класове.

Променлива

Пример за декларация на шаблон и дефиниция е както следва:

шаблон
T pi = 3.14;

Преди да продължите, обърнете внимание, че този вид изявление не може да се появи във функцията main () или в обхвата на блока. Първият ред е декларацията на шаблонната глава, с избраното от програмиста родово име на тип, T. Следващият ред е дефиницията на идентификатора, pi, който е от родов тип, T. Прецизността, независимо дали T е int или float или някакъв друг тип, може да бъде направена във функцията C ++ main () (или друга функция). Такава точност ще бъде направена с променливата pi, а не с T.

Първият ред е декларацията на шаблонната глава. Тази декларация започва със запазената дума, шаблон и след това отворените и затворените ъглови скоби. В ъгловите скоби има поне един родов идентификатор на типа, като T, по-горе. Може да има повече от един родов идентификатор на типа, като всеки от тях се предхожда от запазената дума, typename. Такива общи типове в тази позиция се наричат ​​параметри на шаблона.

Следното изявление може да бъде написано в main () или във всяка друга функция:

Cout << pi << '\n';

И функцията ще покаже 3.14. Изразът pi решава точния тип T за променливата pi. Специализацията решава конкретния тип данни за параметъра на шаблона. Инстантирането е вътрешният процес на C ++ за създаване на конкретния тип, като float, в този случай. Не бъркайте между създаването на пример на параметър на шаблон и създаването на клас. В темата на шаблона много типове данни могат да имат едно родово име на тип, докато много класове могат да имат едно родово име на клас. Общото име на клас за класове обаче се нарича просто клас, а не като име на клас. Също така, стойността е към тип данни, като например int, както екземплярният обект е към клас, като клас String.

При специализацията избраният тип данни, като float, се поставя в ъглови скоби след променливата. Ако в декларацията на шаблонната глава има повече от един параметър на шаблон, в израза за специализация ще има съответния брой типове данни в същия ред.

При специализацията типът е известен като аргумент на шаблон. Не бъркайте между това и аргумента на функцията за извикване на функция.

Тип по подразбиране

Ако при специализацията не е даден тип, се приема типът по подразбиране. И така, от следния израз:

шаблон
U pi = "любов";
дисплеят от:
Cout << pi<> << '\n';

е „любов“ към постоянния указател към char. Забележете в декларацията, че U = const char *. Ъгловите скоби ще бъдат празни при специализация (не е даден тип); действителният тип се счита за const указател на char, типът по подразбиране. Ако при специализацията е необходим друг тип, тогава името на типа ще бъде записано в ъгловите скоби. Когато типът по подразбиране се желае при специализация, повтарянето на типа в ъгловите скоби не е задължително, т.е.д., ъгловите скоби могат да останат празни.

Забележка: Типът по подразбиране все още може да бъде променен при специализация, като има различен тип.

структура

Следващият пример показва как параметър на шаблон може да се използва със структура:

шаблон struct Ages

T Йоан = 11;
T Петър = 12;
T Мери = 13;
T Радост = 14;
;

Това са възрасти на ученици в клас (клас). Първият ред е декларацията на шаблона. Тялото в скоби е действителната дефиниция на шаблона. Възрастите могат да бъдат изведени във функцията main () със следното:

Векове степен7;
Cout << grade7.John << " << grade7.Mary << '\n';

Резултатът е: 11 13. Първото изявление тук извършва специализацията. Обърнете внимание как е направен. Той също така дава име на обект на структурата: grade7. Второто изявление има обикновени изразни обектни изрази. Структурата е като клас. Тук Ages е като име на клас, докато grade7 е обект на класа (struct).

Ако някои възрасти са цели числа, а други са плаващи, тогава структурата се нуждае от два общи параметри, както следва:

шаблон struct Ages

T Йоан = 11;
U Петър = 12.3;
T Мери = 13;
U Радост = 14.6;
;

Съответният код за функцията main () е както следва:

Векове степен7;
Cout << grade7.John << " << grade7.Peter << '\n';

Резултатът е: 11 12.3. При специализацията редът на типовете (аргументите) трябва да съответства на реда на родовите типове в декларацията.

Декларацията на шаблона може да бъде отделена от дефиницията, както следва:

шаблон struct Ages

T John;
U Петър;
T Mary;
U Joy;
;
Векове степен7 = 11, 12.3, 13, 14.6;

Първият кодов сегмент е чисто декларация на шаблон (няма задания). Вторият кодов сегмент, който е само изявление, е дефиницията на идентификатора, степен7. От лявата страна е декларацията на идентификатора, степен7. От дясната страна е списъкът на инициализатора, който присвоява съответните стойности на членовете на структурата. Вторият сегмент (израз) може да бъде записан във функцията main (), докато първият сегмент остава извън функцията main ().

Нетипов

Примерите за типове, които не са данни, включват типове int, указател към обект, указател към функция и автоматични типове. Има и други нетипове, които тази статия не разглежда. Нетипът е като непълен тип, чиято стойност е дадена по-късно и не може да бъде променена. Като параметър той започва с определен нетип, последван от идентификатор. Стойността на идентификатора се дава по-късно при специализация и не може да се променя отново (като константа, чиято стойност се дава по-късно). Следващата програма илюстрира това:

#include
използване на пространство от имена std;
шаблон struct Ages

T John = N;
U Петър = 12.3;
T Мери = N;
U Радост = 14.6;
;
int main ()

Векове степен7;
Cout << grade7.John << " << grade7.Joy << '\n';
връщане 0;

При специализацията първият тип, int, в ъгловите скоби има повече за формалност, за да се уверите, че броят и редът на параметрите съответстват на броя и реда на типовете (аргументи). Стойността на N е дадена при специализация. Резултатът е: 11 14.6.

Частична специализация

Нека приемем, че шаблонът има четири общи типа и че сред четирите типа има нужда от два типа по подразбиране. Това може да се постигне с помощта на конструкцията за частична специализация, която не използва оператора за присвояване. И така, конструкцията за частична специализация дава стойности по подразбиране на подмножество от общи типове. В схемата за частична специализация обаче са необходими основен клас (struct) и частичен клас на специализация (struct). Следващата програма илюстрира това за един родов тип от два родови типа:

#include
използване на пространство от имена std;
// клас на основен шаблон
шаблон
struct Ages

;
// частична специализация
шаблон
struct Ages

Т1 Йоан = 11;
плувка Петър = 12.3;
Т1 Мери = 13;
float Joy = 14.6;
;
int main ()

Векове степен7;
Cout << grade7.John << " << grade7.Joy << '\n';
връщане 0;

Идентифицирайте декларацията за базовия клас и неговата частична дефиниция на клас. Декларацията на шаблонната глава на базовия клас има всички необходими общи параметри. Декларацията на шаблонната глава на класа на частичната специализация има само общ тип. В схемата се използва допълнителен набор от ъглови скоби, който идва непосредствено след името на класа в определението за частична специализация. Това всъщност прави частичната специализация. Той има типа по подразбиране и типа, който не е по подразбиране, в реда, написан в основния клас. Имайте предвид, че типът по подразбиране все още може да получи различен тип във функцията main ().

Съответният код във функцията main () може да бъде както следва:

Векове степен7;
Cout << grade7.John << " << grade7.Joy << '\n';

Резултатът е: 11 14.6.

Пакет с параметри на шаблона

Пакетът от параметри е параметър на шаблон, който приема нула или повече общи типове шаблони за съответните типове данни. Параметърът на пакета с параметри започва със запазена дума тип име или клас. Това е последвано от три точки и след това идентификатора за опаковката. Следващата програма илюстрира как пакет от параметри на шаблон може да се използва със структура:

#include
използване на пространство от имена std;
шаблон struct Ages

int John = 11;
плувка Петър = 12.3;
int Мери = 13;
float Joy = 14.6;
;
int main ()

Векове степен В;
Cout << gradeB.John << " << gradeB.Mary << '\n';
Векове степенC;
Cout << gradeC.Peter << " << gradeC.Joy << '\n';
Векове степенD;
Cout << gradeD.John << " << gradeD.Joy << '\n';
Възраст <> степенA; // като по подразбиране
Cout << gradeA.John << " << gradeA.Joy << '\n';
връщане 0;

Резултатът е:

11 13
12.3 14.6
11 14.6
11 14.6

Шаблони за функции

Посочените по-горе характеристики на шаблона се прилагат по подобен начин на шаблоните за функции. Следващата програма показва функция с два общи параметри на шаблона и три аргумента:

#include
използване на пространство от имена std;
шаблон 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");
връщане 0;

Резултатът е както следва:

В магазина има 12 книги на стойност 500 долара.

Отделяне от прототипа

Дефиницията на функцията може да бъде отделена от нейния прототип, както показва следната програма:

#include
използване на пространство от имена std;
шаблон void func (T no, U cha, const char * str);
шаблон 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");
връщане 0;

Забележка: Декларацията за шаблон на функция не може да се появи във функцията main () или във всяка друга функция.

Претоварване

Претоварването на една и съща функция може да се осъществи с различни декларации на главата на шаблон. Следващата програма илюстрира това:

#include
използване на пространство от имена std;
шаблон void func (T no, U cha, const char * str)

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

шаблон void func (T не, const char * str)

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

int main ()

func (12, '$', "500");
func (12, "500");
връщане 0;

Резултатът е:

В магазина има 12 книги на стойност 500 долара.

В магазина има 12 книги на стойност 500 долара.

Шаблони за класове

Характеристиките на шаблоните, споменати по-горе, се прилагат по подобен начин на шаблоните за класове. Следващата програма е декларацията, дефиницията и използването на прост клас:

#include
използване на пространство от имена std;
клас TheCla

публично:
int num;
статичен символ;
void func (char cha, const char * str)

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

статично празно забавление (char ch)

ако (ch == 'a')
Cout << "Official static member function" << '\n';

;
int main ()

TheCla obj;
обект.num = 12;
обект.func ('$', "500");
връщане 0;

Резултатът е както следва:

В магазина има 12 книги на стойност 500 долара.

Следващата програма е горната програма с декларация на шаблонната глава:

#include
използване на пространство от имена std;
шаблон клас TheCla

публично:
T номер;
статичен U ch;
void func (U cha, const char * str)

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

статично празно забавление (U ch)

ако (ch == 'a')
Cout << "Official static member function" << '\n';

;
int main ()

TheCla obj;
обект.num = 12;
обект.func ('$', "500");
връщане 0;

Вместо думата typename в списъка с параметри на шаблона може да се използва класът дума. Обърнете внимание на специализацията в декларацията на обекта. Резултатът е все същият:

В магазина има 12 книги на стойност 500 долара.

Разделяща декларация

Декларацията на шаблона на класа може да бъде отделена от кода на класа, както следва:

шаблон клас TheCla;
шаблон клас TheCla

публично:
T номер;
статичен U ch;
void func (U cha, const char * str)

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

статично празно забавление (U ch)

ако (ch == 'a')
Cout << "Official static member function" << '\n';

;

Справяне със статични членове

Следващата програма показва как да получите достъп до статичен член на данни и функция на статичен член:

#include
използване на пространство от имена std;
шаблон клас TheCla

публично:
T номер;
статичен U ch;
void func (U cha, const char * str)

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

статично празно забавление (U cha)

ако (ch == 'a')
Cout << "Official static member function" << cha << '\n';

;
шаблон U TheCla:: ch = 'a';
int main ()

TheCla:: забавно ('.');
връщане 0;

Присвояването на стойност на статичен член на данни е декларация и не може да бъде в main (). Обърнете внимание на употребата и позициите на родовите типове и родовия тип данни в израза за присвояване. В допълнение, обърнете внимание, че функцията за статични данни на данни е била извикана в main (), с действителните типове данни на шаблона. Резултатът е следният:

Официална статична функция на члена.

Компилиране

Декларацията (заглавката) и дефиницията на шаблон трябва да бъдат в един файл. Тоест те трябва да са в една и съща преводаческа единица.

Заключение

Шаблоните на C ++ правят алгоритъм независим от типа на използваните данни. Обектите на променлива, функция, структура и клас могат да имат шаблони, които включват декларация и дефиниция. Създаването на шаблон също включва специализация, която е, когато родовият тип взема действителен тип. Декларацията и дефиницията на шаблон трябва да бъдат в една единица за превод.

Урок за OpenTTD
OpenTTD е една от най-популярните бизнес симулационни игри там. В тази игра трябва да създадете прекрасен транспортен бизнес. Въпреки това, ще започне...
SuperTuxKart за Linux
SuperTuxKart е страхотно заглавие, създадено да ви предостави безплатно изживяването на Mario Kart във вашата Linux система. Играта е доста предизвика...
Урок за битка за Уеснот
Битката за Уеснот е една от най-популярните стратегически игри с отворен код, които можете да играете по това време. Тази игра не само се разработва о...