C ++

Como usar modelos C ++

Como usar modelos C ++

Introdução

Na programação C ++ básica, o tipo de dados, e.g., int ou char, deve ser indicado em uma declaração ou definição. Um valor como 4 ou 22 ou -5 é um int. Um valor como 'A' ou 'b' ou 'c' é um caractere. O mecanismo de modelo permite ao programador usar um tipo genérico para um conjunto de tipos reais. Por exemplo, o programador pode decidir usar o identificador T para int ou char. É possível que um algoritmo C ++ tenha mais de um tipo genérico. Com, digamos, T para int ou char, U pode representar o tipo float ou ponteiro. Uma classe, como string ou classe vetorial, é como um tipo de dados, e os objetos instanciados são como valores do tipo de dados, que é a classe especificada. Portanto, o mecanismo de modelo também permite que o programador use um identificador de tipo genérico para um conjunto de classes.

Um modelo C ++ cria um algoritmo independente do tipo de dados empregados. Assim, o mesmo algoritmo, com muitas ocorrências do mesmo tipo, pode usar diferentes tipos em diferentes execuções. As entidades de variável, função, estrutura e classe podem ter modelos. Este artigo explica como declarar modelos, como definir modelos e como aplicá-los em C++. Você já deve ter conhecimento das entidades mencionadas para entender os tópicos abordados neste artigo.

Tipos

Escalar

Os tipos escalares são void, bool, char, int, float e pointer.

Classes como tipos

Uma classe particular pode ser considerada como um tipo e seus objetos como valores possíveis.

Um tipo genérico representa um conjunto de tipos escalares. A lista de tipos escalares é extensa. O tipo int, por exemplo, tem outros tipos relacionados, como short int, long int, etc. Um tipo genérico também pode representar um conjunto de classes.

Variável

Um exemplo de declaração e definição de modelo é o seguinte:

modelo
T pi = 3.14;

Antes de continuar, observe que este tipo de declaração não pode aparecer na função main () ou em qualquer escopo de bloco. A primeira linha é a declaração do template-head, com o nome-tipo genérico escolhido pelo programador, T. A próxima linha é a definição do identificador, pi, que é do tipo genérico, T. A precisão, se o T é um int ou um float ou algum outro tipo, pode ser feita na função main () do C ++ (ou alguma outra função). Tal precisão será feita com a variável pi, e não com T.

A primeira linha é a declaração do template-head. Esta declaração começa com a palavra reservada, modelo e, em seguida, os colchetes angulares abertos e fechados. Dentro dos colchetes angulares, há pelo menos um identificador de tipo genérico, como T, acima. Pode haver mais de um identificador de tipo genérico, com cada um precedido pela palavra reservada, nome de tipo. Esses tipos genéricos nessa posição são chamados de parâmetros de modelo.

A seguinte declaração pode ser escrita em main () ou em qualquer outra função:

cout << pi << '\n';

E a função exibiria 3.14. A expressão pi decide o tipo exato de T para a variável pi. A especialização decide o tipo de dados específico para o parâmetro do modelo. Instanciação é o processo interno C ++ de criação de um tipo específico, como float, neste caso. Não confunda entre instanciar um parâmetro de modelo e instanciar uma classe. No tópico do modelo, muitos tipos de dados podem ter um nome de tipo genérico, enquanto muitas classes podem ter um nome de classe genérico. No entanto, o nome de classe genérico para classes é simplesmente referido como uma classe, e não como um nome de classe. Além disso, um valor está para um tipo de dados, como o int, assim como um objeto instanciado está para uma classe, como a classe String.

Na especialização, o tipo de dado escolhido, como float, é colocado entre colchetes angulares após a variável. Se houver mais de um parâmetro de modelo na declaração do cabeçalho do modelo, haverá um número correspondente de tipos de dados na mesma ordem na expressão de especialização.

Na especialização, um tipo é conhecido como argumento de modelo. Não confunda entre isso e o argumento da função para chamada de função.

Tipo Padrão

Se nenhum tipo for fornecido na especialização, o tipo padrão é assumido. Portanto, a partir da seguinte expressão:

modelo
U pi = "amor";
a exibição de:
cout << pi<> << '\n';

é "amor" para o ponteiro constante para char. Observe na declaração que U = const char *. Os colchetes angulares estarão vazios na especialização (nenhum tipo fornecido); o tipo real é considerado um ponteiro const para char, o tipo padrão. Se algum outro tipo fosse necessário na especialização, o nome do tipo seria escrito entre colchetes angulares. Quando o tipo padrão é desejado na especialização, repetir o tipo nos colchetes é opcional, i.e., os colchetes angulares podem ser deixados vazios.

Nota: o tipo padrão ainda pode ser alterado na especialização por ter um tipo diferente.

estrutura

O exemplo a seguir mostra como um parâmetro de modelo pode ser usado com uma estrutura:

modelo Idade Estrutural

T John = 11;
T Peter = 12;
T Mary = 13;
T Joy = 14;
;

Essas são as idades dos alunos em uma série (classe). A primeira linha é a declaração do modelo. O corpo entre colchetes é a definição real do modelo. As idades podem ser geradas na função main () com o seguinte:

Idades nota 7;
cout << grade7.John << " << grade7.Mary << '\n';

O resultado é: 11 13. A primeira instrução aqui realiza a especialização. Observe como foi feito. Ele também dá um nome para um objeto da estrutura: grade7. A segunda instrução tem expressões de objetos de estrutura comuns. Uma estrutura é como uma classe. Aqui, Ages é como o nome de uma classe, enquanto grade7 é um objeto da classe (struct).

Se algumas idades forem inteiras e outras flutuantes, a estrutura precisará de dois parâmetros genéricos, como segue:

modelo Idade Estrutural

T John = 11;
U Peter = 12.3;
T Mary = 13;
U Joy = 14.6;
;

Um código relevante para a função main () é o seguinte:

Idades nota 7;
cout << grade7.John << " << grade7.Peter << '\n';

O resultado é: 11 12.3. Na especialização, a ordem dos tipos (argumentos) deve corresponder à ordem dos tipos genéricos na declaração.

A declaração do modelo pode ser separada da definição da seguinte forma:

modelo Idade Estrutural

T John;
U Peter;
T Mary;
U Joy;
;
Idades nota 7 = 11, 12.3, 13, 14.6;

O primeiro segmento de código é puramente uma declaração de um modelo (não há atribuições). O segundo segmento de código, que é apenas uma declaração, é a definição do identificador, grau7. O lado esquerdo é a declaração do identificador, grau7. O lado direito é a lista de inicializadores, que atribui valores correspondentes aos membros da estrutura. O segundo segmento (instrução) pode ser escrito na função main (), enquanto o primeiro segmento permanece fora da função main ().

Não Tipo

Exemplos de tipos que não são de dados incluem int, ponteiro para objeto, ponteiro para função e tipos automáticos. Existem outros não tipos, que este artigo não aborda. Um não tipo é como um tipo incompleto, cujo valor é fornecido posteriormente e não pode ser alterado. Como um parâmetro, ele começa com um não-tipo específico, seguido por um identificador. O valor do identificador é fornecido posteriormente, na especialização, e não pode ser alterado novamente (como uma constante, cujo valor é fornecido posteriormente). O programa a seguir ilustra isso:

#incluir
usando namespace std;
modelo Idade Estrutural

T John = N;
U Peter = 12.3;
T Mary = N;
U Joy = 14.6;
;
int main ()

Idades nota 7;
cout << grade7.John << " << grade7.Joy << '\n';
return 0;

Na especialização, o primeiro tipo, int, entre os colchetes é mais para formalidade, para se certificar de que o número e a ordem dos parâmetros correspondem ao número e a ordem dos tipos (argumentos). O valor de N foi dado na especialização. O resultado é: 11 14.6.

Especialização Parcial

Suponhamos que um template tenha quatro tipos genéricos e que, entre os quatro tipos, haja a necessidade de dois tipos padrão. Isso pode ser alcançado usando a construção de especialização parcial, que não emprega o operador de atribuição. Portanto, a construção de especialização parcial fornece valores padrão para um subconjunto de tipos genéricos. No entanto, no esquema de especialização parcial, uma classe base (estrutura) e uma classe de especialização parcial (estrutura) são necessárias. O programa a seguir ilustra isso para um tipo genérico de dois tipos genéricos:

#incluir
usando namespace std;
// classe de modelo base
modelo
Idade Estrutural

;
// especialização parcial
modelo
Idade Estrutural

T1 João = 11;
flutuar Peter = 12.3;
T1 Maria = 13;
float Joy = 14.6;
;
int main ()

Idades nota 7;
cout << grade7.John << " << grade7.Joy << '\n';
return 0;

Identifique a declaração da classe base e sua definição parcial de classe. A declaração do template-head da classe base tem todos os parâmetros genéricos necessários. A declaração template-head da classe de especialização parcial tem apenas o tipo genérico. Existe um conjunto extra de colchetes angulares usados ​​no esquema que vem logo após o nome da classe na definição de especialização parcial. É o que realmente faz a especialização parcial. Possui o tipo padrão e o tipo não padrão, na ordem escrita na classe base. Observe que o tipo padrão ainda pode receber um tipo diferente na função main ().

O código relevante na função main () pode ser o seguinte:

Idades nota 7;
cout << grade7.John << " << grade7.Joy << '\n';

O resultado é: 11 14.6.

Pacote de parâmetros de modelo

Um pacote de parâmetros é um parâmetro de modelo que aceita zero ou mais tipos genéricos de modelo para os tipos de dados correspondentes. O parâmetro do pacote de parâmetros começa com a palavra reservada nome de tipo ou classe. Isso é seguido por três pontos e, em seguida, o identificador do pacote. O programa a seguir ilustra como um pacote de parâmetros de modelo pode ser usado com uma estrutura:

#incluir
usando namespace std;
modelo Idade Estrutural

int John = 11;
flutuar Peter = 12.3;
int Mary = 13;
float Joy = 14.6;
;
int main ()

Idades Série b;
cout << gradeB.John << " << gradeB.Mary << '\n';
Idades gradeC;
cout << gradeC.Peter << " << gradeC.Joy << '\n';
Idades gradeD;
cout << gradeD.John << " << gradeD.Joy << '\n';
Idades <> grauA; // como padrão
cout << gradeA.John << " << gradeA.Joy << '\n';
return 0;

O resultado é:

11 13
12.3 14.6
11 14.6
11 14.6

Modelos de Função

Os recursos do modelo mencionados acima se aplicam de maneira semelhante aos modelos de função. O programa a seguir mostra uma função com dois parâmetros de modelo genéricos e três argumentos:

#incluir
usando namespace std;
modelo void func (T no, U cha, const char * str)

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

int main ()

função (12, '$', "500");
return 0;

O resultado é o seguinte:

Existem 12 livros no valor de $ 500 na loja.

Separação do Protótipo

A definição da função pode ser separada de seu protótipo, como mostra o seguinte programa:

#incluir
usando namespace std;
modelo void func (T no, U cha, const char * str);
modelo void func (T no, U cha, const char * str)

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

int main ()

função (12, '$', "500");
return 0;

Nota: A declaração do modelo de função não pode aparecer na função main () ou em qualquer outra função.

Sobrecarregando

A sobrecarga da mesma função pode ocorrer com diferentes declarações de template-head. O programa a seguir ilustra isso:

#incluir
usando namespace std;
modelo void func (T no, U cha, const char * str)

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

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

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

int main ()

função (12, '$', "500");
função (12, "500");
return 0;

O resultado é:

Existem 12 livros no valor de $ 500 na loja.

Existem 12 livros no valor de $ 500 na loja.

Modelos de classes

Os recursos dos modelos mencionados acima se aplicam de maneira semelhante aos modelos de classe. O programa a seguir é a declaração, definição e uso de uma classe simples:

#incluir
usando namespace std;
classe TheCla

público:
int num;
estático char ch;
void func (char cha, const char * str)

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

static void fun (char ch)

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

;
int main ()

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

O resultado é o seguinte:

Existem 12 livros no valor de $ 500 na loja.

O programa a seguir é o programa acima com uma declaração de template-head:

#incluir
usando namespace std;
modelo classe TheCla

público:
T num;
estático U ch;
void func (U cha, const char * str)

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

static void fun (U ch)

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

;
int main ()

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

Em vez da palavra typename na lista de parâmetros do modelo, a palavra class pode ser usada. Observe a especialização na declaração do objeto. O resultado ainda é o mesmo:

Existem 12 livros no valor de $ 500 na loja.

Declaração de Separação

A declaração do modelo de classe pode ser separada do código da classe, da seguinte maneira:

modelo class TheCla;
modelo classe TheCla

público:
T num;
estático U ch;
void func (U cha, const char * str)

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

static void fun (U ch)

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

;

Lidando com membros estáticos

O programa a seguir mostra como acessar um membro de dados estáticos e uma função de membro estático:

#incluir
usando namespace std;
modelo classe TheCla

público:
T num;
estático U ch;
void func (U cha, const char * str)

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

diversão void estática (U cha)

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

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

TheCla::Diversão('.');
return 0;

Atribuir um valor a um membro de dados estáticos é uma declaração e não pode estar em main (). Observe o uso e as posições dos tipos genéricos e do tipo genérico de dados na instrução de atribuição. Além disso, observe que a função-membro de dados estáticos foi chamada em main (), com os tipos de dados de modelo reais. O resultado é o seguinte:

Função de membro estático oficial.

Compilando

A declaração (cabeçalho) e a definição de um modelo devem estar em um arquivo. Ou seja, eles devem estar na mesma unidade de tradução.

Conclusão

Os modelos C ++ fazem um algoritmo independente do tipo de dados empregados. As entidades de variável, função, estrutura e classe podem ter modelos, que envolvem declaração e definição. A criação de um modelo também envolve especialização, que ocorre quando um tipo genérico assume um tipo real. A declaração e a definição de um modelo devem estar em uma unidade de tradução.

O cursor pula ou se move aleatoriamente enquanto digita no Windows 10
Se você descobrir que o cursor do mouse pula ou se move por conta própria, de forma automática e aleatória ao digitar em um laptop ou computador com W...
Como reverter a direção de rolagem do Mouse e Touchpads no Windows 10
Mouse e Touchpads não apenas torna a computação mais fácil, mas mais eficiente e menos demorada. Não podemos imaginar uma vida sem esses dispositivos,...
Como alterar o ponteiro do mouse e tamanho do cursor, cor e esquema no Windows 10
O ponteiro do mouse e o cursor no Windows 10 são aspectos muito importantes do sistema operacional. Isso também pode ser dito para outros sistemas ope...