preview
Do básico ao intermediário: Herança

Do básico ao intermediário: Herança

MetaTrader 5Exemplos | 14 maio 2025, 08:47
57 0
CODE X
CODE X

Introdução

No artigo anterior Do básico ao intermediário: Estruturas (VII), começamos a trabalhar com uma programação estrutural que se mostra muito divertida e interessante. Apesar de parecer bastante complexa e difícil durante o primeiro contato que temos com aquele tipo de coisa. Sei dito, pois tive bastante dificuldade no início, para conseguir compreender por que alguns códigos funcionavam enquanto outros era muito difícil de fazer dar certo. Foram anos de muita luta e persistência até aprender de maneira definitiva, os conceitos que estou tentando passar aqui nestes artigos.

Muitos imaginam que podemos aprender a programar, fazendo um curso ou simplesmente estudando códigos de outros programadores. Porém lamento informar, que para realmente aprender a programar, você precisa de fato praticar. E somente com o tempo e resolvendo problemas atrás de problemas é que você de fato irá se tornar um bom profissional. E isto leva tempo. Mas se posso ajudar a acelerar um pouco as coisas. Por que não passar parte deste meu conhecimento, para quem realmente deseja aprender?

Pois bem, então chegamos em um ponto chave. Onde as coisas irão começar a ficar ainda mais interessantes e divertidas. Apesar de que, é muito importante, que você tenha conseguido estabelecer uma boa base, e tenha de fato conseguido entender o que foi explicado nos artigos anteriores. Pois de agora em diante, sem que você de fato tenha estudado e praticado o que foi visto antes. Será muito difícil continuar acompanhando este e os próximos artigos.


Herança simples

Uma das coisas que muita gente acredita de maneira completamente errônea, que somente existe em códigos de classe. Ou como é comumente chamada, programação orientada em objetos. É a também conhecida herança. E o que seria uma herança? Bem, de forma bastante simplificada, é quando podemos criar um tipo de dado simples, e depois, com base neste tipo simples criar outros mais complexos. Porém, sem precisar criar elementos, funções e procedimentos, que tenham sido previamente estabelecidos no que seria este tipo de dado mais simples.

Para entender isto, de maneira mais adequada, pense no seguinte tipo de coisa. Na natureza, existem diversos tipos de animais, plantas e minerais. Suponhamos que você, precise criar um código para organizar cada informação de entrada no que seria estes tipos presentes na natureza. Que no caso resumimos como sendo animais, plantas e minerais. Como você faria isto? Muito provavelmente você criaria três tipos de estruturas, a fim de conseguir separar cada informação de entrada em um destes tipos previamente definidos.

Ao criar tais estruturas, você acabaria notando que poderia tornar o código mais fácil de manipular e entender, se fosse feita uma programação totalmente estruturada. Isto foi visto nos artigos anteriores. Porém, animais e plantas, tem uma coisa em comum entre eles. Ambos são organismos vivos. Diferente dos minerais. Sendo assim, tanto plantas quanto animais, têm elementos estruturais que são iguais entre si.

Tais elementos podem ser removidos e colocados no que seria uma nova estrutura base. Com isto teríamos algo comum entre os seres vivos, que evitaria a duplicação de código dentro da própria estrutura de dados. Facilitando assim, tanto a manutenção do código, quanto a própria implementação e melhoria do mesmo.

Normalmente a maior parte do código, que visa trabalhar e operar no mercado financeiro, usando para isto o MetaTrader 5 e por consequência o MQL5. Não precisa de tal nível de abstração que estou introduzindo neste artigo. Tal pouco, precisa fazer uso de programação estrutural ou mesmo orientada em objetos para tal proposito.

Porém, devido a própria natureza da programação em si, e do tipo de problema que podemos vier a enfrentar. É extremamente útil e necessário, que você meu caro leitor, consiga compreender estes mecanismos e conceitos que estou mostrando aqui. Não que você venha a de fato necessitar dos mesmos. Mas sim por que, para criar algo, com um menor esforço e trabalho, será sim necessário entender o como certas coisas funcionam. E para isto entender estes conceitos, aparentemente sem sentido e complicados, acabará tornando as coisas muito mais simples no futuro.

Novamente, não precisamos entender programação estrutural para criar um Expert Advisor, e tão pouco um indicador. Visto que podemos fazer isto, usando diretamente um modo convencional de programação. Se você dúvida disto que acabo de falar, veja este meu primeiro artigo Desenvolvendo um EA de negociação do zero. Lá sem usar absolutamente nada de programação estrutural e tão pouco programação orientada em objetos. Mostrei como criar um simples Expert Advisor, que nos permite enviar ordens diretamente no gráfico.

A mesma coisa se aplica a indicadores, onde no artigo Do básico ao intermediário: Indicador (IV), mostrei como poderíamos plotar um indicador no gráfico. Tudo isto, é simples e não precisa de muito conhecimento. Apenas necessita de bom senso e entender a documentação do MQL5, para conseguir criar o aplicativo desejado.

Então, definido esta separação do que é ou não preciso saber, para criar as coisas. Podemos voltar ao nosso exemplo hipotético. Como sabemos que existem elementos comuns entre vivos e não vivos. Podemos separar as coisas de uma forma lógica e agradável. Tanto pelo ponto de vista de implementação, quanto pelo ponto de vista de manutenção e usabilidade de funções e procedimentos.

Para tornar isto devidamente entendido, vamos voltar nossa atenção a um dos códigos vistos no artigo anterior. O mesmo pode ser visto, sendo replicado logo abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. struct st_Reg
005. {
006.     //+----------------+
007.     private:
008.     //+----------------+
009.         string  h_value;
010.         uint    k_value;
011.     //+----------------+
012.     public:
013.     //+----------------+
014.         void Set(const uint arg1, const string arg2)
015.         {
016.             k_value = arg1;
017.             h_value = arg2;
018.         }
019.     //+----------------+
020.         uint Get_K(void)    { return k_value; }
021.     //+----------------+
022.         string Get_H(void)  { return h_value; }
023.     //+----------------+
024. };
025. //+------------------------------------------------------------------+
026. struct st_Bio
027. {
028.     //+----------------+
029.     private:
030.     //+----------------+
031.         string  h_value;
032.         string  b_value;
033.         uint    k_value;
034.     //+----------------+
035.     public:
036.     //+----------------+
037.         void Set(const uint arg1, const string arg2, const string arg3)
038.         {
039.             k_value = arg1;
040.             h_value = arg2;
041.             b_value = arg3;
042.         }
043.     //+----------------+
044.         uint Get_K(void)    { return k_value; }
045.     //+----------------+
046.         bool Get_Bio(string &arg1, string &arg2)
047.         {
048.             arg1 = h_value;
049.             arg2 = b_value;
050. 
051.             return true;
052.         }
053.     //+----------------+
054. };
055. //+------------------------------------------------------------------+
056. template <typename T>
057. struct st_Data
058. {
059.     //+----------------+
060.     private:
061.     //+----------------+
062.         T Values[];
063.     //+----------------+
064.     public:
065.     //+----------------+
066.         bool Set(const T &arg)
067.         {
068.             if (ArrayResize(Values, Values.Size() + (Values.Size() == 0 ? 2 : 1)) == INVALID_HANDLE)
069.                 return false;
070. 
071.             Values[Values.Size() - 1] = arg;
072. 
073.             return true;
074.         }
075.     //+----------------+
076.         T Get(const uint index)
077.         {
078.             for (uint c = 0; c < Values.Size(); c++)
079.                 if (Values[c].Get_K() == index)
080.                     return Values[c];
081. 
082.             return Values[0];
083.         }
084.     //+----------------+
085. };
086. //+------------------------------------------------------------------+
087. #define PrintX(X) Print(#X, " => [", X, "]")
088. //+------------------------------------------------------------------+
089. void CheckBio(st_Data <st_Bio> &arg)
090. {
091.     string sz[2];
092. 
093.     Print("Checking data in the structure...");
094.     for (uint i = 7; i < 11; i += 3)
095.     {
096.         Print("Index: ", i, " Result: ");
097.         if (arg.Get(i).Get_Bio(sz[0], sz[1]))
098.             ArrayPrint(sz);
099.         else
100.             Print("Failed.");
101.     }
102. }
103. //+------------------------------------------------------------------+
104. void OnStart(void)
105. {
106.     const string T = "possible loss of data due to type conversion";
107.     const string M[] = {"2", "cool", "4", "zero", "mad", "five", "what", "xoxo"};
108.     const uint   K[] = {2, 1, 4, 0, 7, 5, 3, 6};
109. 
110.     st_Data <st_Reg> Info_1;
111.     st_Data <st_Bio> Info_2;
112. 
113.     string  H[];
114. 
115.     StringSplit(T, ' ', H);
116.     for (uint c = 0; c < H.Size(); c++)
117.     {
118.         st_Reg  reg;
119.         st_Bio  bio;
120. 
121.         reg.Set(K[c], H[c]);
122.         bio.Set(K[c], M[c], H[c]);
123. 
124.         Info_1.Set(reg);
125.         Info_2.Set(bio);
126.     }
127. 
128.     PrintX(Info_1.Get(3).Get_H());
129.     PrintX(Info_1.Get(13).Get_H());
130.     CheckBio(Info_2);
131. }
132. //+------------------------------------------------------------------+

Código 01

Quando executamos este código 01, teremos como resultado o que é mostrado na imagem logo abaixo.

Imagem 01

Agora, vem a parte onde quero chegar. Da mesma forma que animais e plantas têm elementos em comum, aqui no código 01, temos k_value como elemento comum. Tanto para st_Reg, quanto para st_Bio. Mas ambas estruturas não estão conversando entre si. Sendo cada uma estrutura completamente distinta uma da outra. De maneira visual, temos o que é mostrado na imagem logo abaixo.

Imagem 02

Ou seja, duas entidades distintas entre si. Porém com coisas comuns entre elas. E isto, é que seria a tal da duplicação de código. Já que elementos comuns, com a mesma forma de serem manipulados e acessados. Não precisam de fato estarem separados entre si. Isto apenas dificulta e complica o código de maneira totalmente desnecessária.

Para que isto fique claro. Pense no seguinte fato: Você resolve, melhorar por qualquer motivo a função Get_K, presente na estrutura st_Reg. Ao fazer isto, nota que o código geral ficou bem melhor. Mas, não faz a mesma coisa em st_Bio. Quando você vier a utilizar ambas estruturas ao mesmo tempo, acaba percebendo que st_Bio, apesar de usar Get_K, não está tendo o mesmo comportamento que st_Reg.

E é neste ponto que começa os problemas. Pois você, copia o código de Get_K, presente na estrutura st_Reg para a estrutura st_Bio. E depois de um tempo, nota que precisa mexer novamente no código Get_K. E terá que fazer isto em ambas estruturas.

Além de ser uma baita perda de tempo. Este tipo de coisa dificulta enormemente a melhoria do código. Pois aqui, estamos usando apenas duas estruturas. Em um código real, pode haver dezenas ou até mesmo centenas de estruturas que tem algo comum em todas elas. Pense só em ter que corrigir e fazer a manutenção neste tipo de código? É uma trabalheira infernal. Porém existe uma forma simples e muito prática de tornar todo este trabalho mais simples, fácil, rápido e seguro. Esta maneira envolve justamente o uso de herança.

Uma herança, nada mais é do que pegar esta parte comum em ambas estruturas e a colocar em uma outra estrutura. E depois, de alguma forma, fazer com que a estrutura consiga usar o código que está sendo herdado. Falando assim, parece complicado. Mas na prática, você verá que é muito mais simples de se fazer isto, do que você provavelmente deva estar imaginando.

Então vamos colocar isto em prática. Fazendo com que o código 01, venha a fazer uso de herança. Para conseguir fazer isto, o primeiro passo a ser feito, é mostrado no fragmento de código, visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_Base
05. {
06.     private:
07.         uint KeyValue;
08.     public:
09.     //+----------------+
10.         void SetKey(const uint arg) { KeyValue = arg; }
11.     //+----------------+
12.         uint GetKey(void) { return KeyValue; }
13. };
14. //+------------------------------------------------------------------+
15. struct st_Reg
16. {
17.     private:
18.         string  Value;
19.     public:
20.     //+----------------+
21.         void SetValue(const uint arg1, const string arg2)
22.         {
23.             Value = arg2;
24.         }
25.     //+----------------+
26.         string GetValue(void)  { return Value; }
27. };
28. //+------------------------------------------------------------------+
29. struct st_Bio
30. {
31.     private:
32.         string  Value[2];
33.     public:
34.     //+----------------+
35.         void SetValue(const uint arg1, const string arg2, const string arg3)
36.         {
37.             Value[0] = arg2;
38.             Value[1] = arg3;
39.         }
40.     //+----------------+
41.         bool GetValue(string &arg1, string &arg2)
42.         {
43.             arg1 = Value[0];
44.             arg2 = Value[1];
45. 
46.             return true;
47.         }
48.     //+----------------+
49. };
50. //+------------------------------------------------------------------+
                   .
                   .
                   .

Código 02

Neste fragmento mostrado no código 02, podemos ver que foi criada uma nova estrutura. Esta atende pelo nome de st_Base. Agora preste atenção, meu caro leitor. Apesar de eu ter melhorado a questão das variáveis vistas neste fragmento que é o código 02. Ele ainda assim contém o mesmo número e tipo de variáveis vistas no código 01. Porém ele apenas está melhor organizado. Porém a grande verdete aqui é de fato esta estrutura st_Base. Com isto tendo sido feito, o que temos agora é mostrado logo abaixo

Imagem 03

Note que se parece bastante com a imagem 02. No entanto, esta imagem 03, não está fazendo uso da herança. Isto por conta que o fragmento mostrado no código 02, também não está fazendo isto. Então se neste ponto, você tentar compilar o código 01, usando este fragmento mostrado no código 02. Irá receber diversos erros sendo informado pelo compilador. Para corrigir isto, precisamos que esta imagem 03, se transforme nesta imagem 04, vista logo abaixo.

Imagem 04

Aqui nesta imagem 04, as setas indicam como a herança irá ser feita. Ou seja, iremos jogar o conteúdo da estrutura st_Base para dentro das estruturas st_Bio e st_Reg, sem mexer muito no código. E para fazer isto, tudo que precisamos fazer é mudar o código 02 para o código visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_Base
05. {
06.     private:
07.         uint KeyValue;
08.     public:
09.     //+----------------+
10.         void SetKey(const uint arg) { KeyValue = arg; }
11.     //+----------------+
12.         uint GetKey(void) { return KeyValue; }
13. };
14. //+------------------------------------------------------------------+
15. struct st_Reg : public st_Base
16. {
17.     private:
18.         string  Value;
19.     public:
20.     //+----------------+
21.         void SetValue(const uint arg1, const string arg2)
22.         {
23.             Value = arg2;
24.         }
25.     //+----------------+
26.         string GetValue(void)  { return Value; }
27. };
28. //+------------------------------------------------------------------+
29. struct st_Bio : public st_Base
30. {
31.     private:
32.         string  Value[2];
33.     public:
34.     //+----------------+
35.         void SetValue(const uint arg1, const string arg2, const string arg3)
36.         {
37.             Value[0] = arg2;
38.             Value[1] = arg3;
39.         }
40.     //+----------------+
41.         bool GetValue(string &arg1, string &arg2)
42.         {
43.             arg1 = Value[0];
44.             arg2 = Value[1];
45. 
46.             return true;
47.         }
48.     //+----------------+
49. };
50. //+------------------------------------------------------------------+
                   .
                   .
                   .

Código 03

Uau, veja o qual complicado foi implementar a herança no código. Porém, você pode notar que existem referência a valores que ainda não foram resolvidos neste fragmento mostrado no código 03. Isto porque, neste fragmento, apenas implementamos a herança. Porém ainda não a estamos utilizando na prática e de forma a permitir que as informações sobre KeyValue sejam de fato aplicadas. Isto a fim de permitir que st_Data consiga estabelecer uma ligação entre os dados a fim de construir o que é visto na imagem 01.

Para resolver tais ligações, precisamos mexer mais uma vez no código. E com isto ele irá ficar como mostrado logo abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. struct st_Base
005. {
006.     private:
007.         uint KeyValue;
008.     public:
009.     //+----------------+
010.         void SetKey(const uint arg) { KeyValue = arg; }
011.     //+----------------+
012.         uint GetKey(void) { return KeyValue; }
013. };
014. //+------------------------------------------------------------------+
015. struct st_Reg : public st_Base
016. {
017.     private:
018.         string  Value;
019.     public:
020.     //+----------------+
021.         void SetValue(const uint arg1, const string arg2)
022.         {
023.             SetKey(arg1);
024.             Value = arg2;
025.         }
026.     //+----------------+
027.         string GetValue(void)  { return Value; }
028. };
029. //+------------------------------------------------------------------+
030. struct st_Bio : public st_Base
031. {
032.     private:
033.         string  Value[2];
034.     public:
035.     //+----------------+
036.         void SetValue(const uint arg1, const string arg2, const string arg3)
037.         {
038.             SetKey(arg1);
039.             Value[0] = arg2;
040.             Value[1] = arg3;
041.         }
042.     //+----------------+
043.         bool GetValue(string &arg1, string &arg2)
044.         {
045.             arg1 = Value[0];
046.             arg2 = Value[1];
047. 
048.             return true;
049.         }
050.     //+----------------+
051. };
052. //+------------------------------------------------------------------+
053. template <typename T>
054. struct st_Data
055. {
056.     private:
057.         T Values[];
058.     public:
059.     //+----------------+
060.         bool Set(const T &arg)
061.         {
062.             if (ArrayResize(Values, Values.Size() + (Values.Size() == 0 ? 2 : 1)) == INVALID_HANDLE)
063.                 return false;
064. 
065.             Values[Values.Size() - 1] = arg;
066. 
067.             return true;
068.         }
069.     //+----------------+
070.         T Get(const uint index)
071.         {
072.             for (uint c = 0; c < Values.Size(); c++)
073.                 if (Values[c].GetKey() == index)
074.                     return Values[c];
075. 
076.             return Values[0];
077.         }
078. };
079. //+------------------------------------------------------------------+
080. #define PrintX(X) Print(#X, " => [", X, "]")
081. //+------------------------------------------------------------------+
082. void CheckBio(st_Data <st_Bio> &arg)
083. {
084.     string sz[2];
085. 
086.     Print("Checking data in the structure...");
087.     for (uint i = 7; i < 11; i += 3)
088.     {
089.         Print("Index: ", i, " Result: ");
090.         if (arg.Get(i).GetValue(sz[0], sz[1]))
091.             ArrayPrint(sz);
092.         else
093.             Print("Failed.");
094.     }
095. }
096. //+------------------------------------------------------------------+
097. void OnStart(void)
098. {
099.     const string T = "possible loss of data due to type conversion";
100.     const string M[] = {"2", "cool", "4", "zero", "mad", "five", "what", "xoxo"};
101.     const uint   K[] = {2, 1, 4, 0, 7, 5, 3, 6};
102. 
103.     st_Data <st_Reg> Info_1;
104.     st_Data <st_Bio> Info_2;
105. 
106.     string  H[];
107. 
108.     StringSplit(T, ' ', H);
109.     for (uint c = 0; c < H.Size(); c++)
110.     {
111.         st_Reg  reg;
112.         st_Bio  bio;
113. 
114.         reg.SetValue(K[c], H[c]);
115.         bio.SetValue(K[c], M[c], H[c]);
116. 
117.         Info_1.Set(reg);
118.         Info_2.Set(bio);
119.     }
120. 
121.     PrintX(Info_1.Get(3).GetValue());
122.     PrintX(Info_1.Get(13).GetValue());
123.     CheckBio(Info_2);
124. }
125. //+------------------------------------------------------------------+

Código 04

Este código 04, tem o mesmo efeito, ou resultado que o código 01. No entanto, aqui neste código 04, estamos fazendo uso da herança entre estruturas. Então qualquer melhoria que por ventura você vier a fazer na estrutura st_Base. Todo o código irá se beneficiar automaticamente. Ou seja, qualquer mudança, por menor que venha a ser feita, na estrutura st_Base. Tanto st_Reg, quanto st_Bio, irão automaticamente obter acesso a esta mudança.

Desde é claro, o procedimento, função ou variável, venha a ser colocada dentro do que seria a clausula pública. Se for feita uma adição, porém dentro da clausula privativa da estrutura st_Base. Nem st_Reg, e tão pouco st_Bio irão ficar cientes de tal adição. Sendo que esta ficará restrita a somente ser utilizada pela classe st_Base.

Um ponto que não cometei no código 04, e que pode vir a ser importante, é o fato de que nas linhas 15 e 30, a herança está sendo feita de forma pública. Isto permite que qualquer variável que venha a ser do tipo de uma das duas estruturas, terá acesso também a qualquer coisa pública dentro da estrutura st_Base. Se no lugar destas palavras reservadas public, que podem ser vistas nas linhas mencionadas. Estivéssemos usando a palavra private. Qualquer variável que vier a utilizar a estrutura, seja ela st_Bio ou st_Reg, não teria acesso ao que esteja na estrutura st_Base. Experimente fazer isto depois, com o arquivo que estará no anexo para entender melhor este tipo de coisa, meu caro leitor.

Como o assunto principal deste artigo é a herança. Que tal brincarmos um pouco com este tema. Porém de uma forma um pouco mais divertida. Para isto, vamos a um novo tópico. Pois não quero que você fique apavorado, e imagine que estarei mostrando algo que só um profissional altamente gabaritado conseguiria fazer. Pois isto não seria de fato verdade. Qualquer um de vocês, que estão estudando e acompanhando esta série de artigos que estou postando conseguiriam fazer algo parecido.

Claro que para isto, seria preciso entender e aplicar certos conceitos que foram mostrados e explicados nos artigos anteriores. Então vamos a festa do pijama, pois, se você achou divertido o que foi feito até aqui, irá se maravilhar com o que iremos ver agora.


Estruturas, templates e herança: Uma combinação do barulho

Muita gente não faz ideia do quanto o MQL5, mesmo que não tenha todas as capacidades do C e C++, consegue de fato fazer. E olha que perto do C e C++, programar em MQL5 é muito mais simples e fácil. Se estes artigos fossem sobre C e C++, acredito que muitos de vocês já teriam desistido e procurado fazer outra coisa da vida. Mas como aqui estou focado em tratar apenas sobre como programar em MQL5. Os artigos em sua maioria serão constituídos de coisas muito simples. Mas que por serem pouco exploradas por muitos, acaba se tornando algo quase que místico.

Uma destas coisas é o uso combinado de tudo que foi visto até aqui. Ou seja, será que podemos combinar uma programação estrutural, com a possibilidade de sobrecarga de estruturas e ao mesmo tempo usar herança em um código único? Sim, meu caro leitor. E por mais que isto possa parecer material avançado, ele ainda assim, no meu conceito é um material básico. Só que um pouco mais elaborado do que todo o resto visto até este momento.

No entanto, se você estudar e pensar um pouco, sobre os conceitos mostrados até este momento. Acabará pensando em como poderia unir todas estas coisas em um código realmente bem interessante. Visto que, podemos usar algo que para muitos necessitaria escrever um monte de código. Mas iremos fazer isto, com um código muito simples. E deixar todo o peso, para o compilador resolver.

Como não quero lhe assustar, com lhe mostrando como o código visto no tópico anterior, ficaria, ao usarmos todos estes recursos ao mesmo tempo. Vamos começar fazendo as coisas com calma. Assim, você vai se acostumado com a ideia, ao mesmo tempo que irá perceber como é importante entender conceitos. E não tentar ficar decorando e copiando códigos a esmo, tentando fazer eles funcionarem depois.

Bem, o nosso código irá começar da seguinte forma, mostrada abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_Base
05. {
06.     private :
07.         uint KeyValue;
08.     public  :
09.     //+----------------+
10.         void SetKey(const uint arg)
11.         {
12.             KeyValue = arg;
13.         }
14.     //+----------------+
15.         uint GetKey(void)
16.         {
17.             return KeyValue;
18.         }
19.     //+----------------+
20. };
21. //+------------------------------------------------------------------+

Código 05

Ok, acredito que todos conseguem entender este código 05. Então podemos ir o que seria o próximo passo na implementação.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_Base
05. {
06.     private :
07.         uint KeyValue;
08.     public  :
09.     //+----------------+
10.         void SetKey(const uint arg)
11.         {
12.             KeyValue = arg;
13.         }
14.     //+----------------+
15.         uint GetKey(void)
16.         {
17.             return KeyValue;
18.         }
19.     //+----------------+
20. };
21. //+------------------------------------------------------------------+
22. struct st_Dev01 : public st_Base
23. {
24.     private :
25.         string ValueInfo;
26.     public  :
27.     //+----------------+
28.         void SetKeyInfo(uint arg1, string arg2)
29.         {
30.             SetKey(arg1);
31.             ValueInfo = arg2;
32.         }
33.     //+----------------+
34.         string GetInfo(void)
35.         {
36.             return ValueInfo;
37.         }
38.     //+----------------+
39. }
40. //+------------------------------------------------------------------+

Código 06

Legal, agora já implementados a parte referente a herança. Temos assim duas estruturas bem simples e que são bastante básicas. Agora chegou a hora do próximo passo. Neste momento, vamos implementar o que poderia ser considerado uma lista. Isto também é bem simples, e pode ser visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_Base
05. {
06.     private :
07.         uint KeyValue;
08.     public  :
09.     //+----------------+
10.         void SetKey(const uint arg)
11.         {
12.             KeyValue = arg;
13.         }
14.     //+----------------+
15.         uint GetKey(void)
16.         {
17.             return KeyValue;
18.         }
19.     //+----------------+
20. };
21. //+------------------------------------------------------------------+
22. struct st_Dev01 : public st_Base
23. {
24.     private :
25.         string ValueInfo;
26.     public  :
27.     //+----------------+
28.         void SetKeyInfo(uint arg1, string arg2)
29.         {
30.             SetKey(arg1);
31.             ValueInfo = arg2;
32.         }
33.     //+----------------+
34.         string GetInfo(void)
35.         {
36.             return ValueInfo;
37.         }
38.     //+----------------+
39. };
40. //+------------------------------------------------------------------+
41. struct st_List
42. {
43.     private :
44.         st_Dev01    List[];
45.         uint        nElements;
46.     public  :
47.     //+----------------+
48.         void Clear(void)
49.         {
50.             ArrayFree(List);
51.             nElements = 0;
52.         }
53.     //+----------------+
54.         bool AddList(const st_Dev01 &arg)
55.         {
56.             nElements += (nElements == 0 ? 2 : 1);
57.             ArrayResize(List, nElements);
58.             List[nElements - 1] = arg;
59. 
60.             return true;
61. 
62.         }
63.     //+----------------+
64.         st_Dev01 SearchKey(const uint arg)
65.         {
66.             for (uint c = 1; c < nElements; c++)
67.                 if (List[c].GetKey() == arg)
68.                     return List[c];
69. 
70.             return List[0];
71.         }
72.     //+----------------+
73. };
74. //+------------------------------------------------------------------+

Código 07

Note que até agora, não fizemos nada diferente do que foi feito anteriormente. Tudo continua da mesma forma. Simples e didático. Agora vamos criar uma pequena lista de informações, para verificar se tudo está funcionando. Isto será feito no código que pode ser visto imediatamente abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. #define PrintX(X) Print(#X, " => [", X, "]")
07. //+------------------------------------------------------------------+
08. void OnStart(void)
09. {
10.     const string Names[] = 
11.         {
12.             "Daniel Jose",
13.             "Edimarcos Alcantra",
14.             "Carlos Almeida",
15.             "Yara Alves"
16.         };
17. 
18.     st_List list;
19. 
20.     for (uint c = 0; c < Names.Size(); c++)
21.     {
22.         st_Dev01 info;
23. 
24.         info.SetKeyInfo(c, Names[c]);
25.         list.AddList(info);
26.     }
27. 
28.     PrintX(list.SearchKey(2).GetInfo());
29. }
30. //+------------------------------------------------------------------+

Código 08

Agora veja que todo aquele código, que foi visto e está presente em código 07, era na verdade um arquivo de cabeçalho. Este é adicionado ao código 08, na linha quatro. Na linha 10 criamos um pequeno array contendo alguns nomes. Na linha 18, temos a nossa estrutura de dados. Já na linha 25 criamos a estrutura propriamente dita. Então na linha 28, usando uma chave, procuramos qual a informação que pertence aquela chave específica. Com isto temos como resposta da execução do código o que pode ser visto logo abaixo.

Imagem 05

Ok, nada demais. Tudo conforme era esperado e já havia sido mostrado e estudado, até aqui. Mas agora vem a novidade, e junto com ela um verdadeiro parque de diversões. Isto porque agora iremos incluir a sobrecarga neste sistema de lista. E para tornar a coisas menos assustadora possível. Vamos começar detrás para frente. Desta forma, o código do arquivo de cabeçalho será modificado para que fique como mostrado abaixo. Lembrando que o código do arquivo de cabeçalho, seria o código 07, originalmente.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_Base
05. {
06.     private :
07.         uint KeyValue;
08.     public  :
09.     //+----------------+
10.         void SetKey(const uint arg)
11.         {
12.             KeyValue = arg;
13.         }
14.     //+----------------+
15.         uint GetKey(void)
16.         {
17.             return KeyValue;
18.         }
19.     //+----------------+
20. };
21. //+------------------------------------------------------------------+
22. struct st_Dev01 : public st_Base
23. {
24.     private :
25.         string ValueInfo;
26.     public  :
27.     //+----------------+
28.         void SetKeyInfo(uint arg1, string arg2)
29.         {
30.             SetKey(arg1);
31.             ValueInfo = arg2;
32.         }
33.     //+----------------+
34.         string GetInfo(void)
35.         {
36.             return ValueInfo;
37.         }
38.     //+----------------+
39. };
40. //+------------------------------------------------------------------+
41. template <typename T>
42. struct st_List
43. {
44.     private :
45.         T    List[];
46.         uint nElements;
47.     public  :
48.     //+----------------+
49.         void Clear(void)
50.         {
51.             ArrayFree(List);
52.             nElements = 0;
53.         }
54.     //+----------------+
55.         bool AddList(const T &arg)
56.         {
57.             nElements += (nElements == 0 ? 2 : 1);
58.             ArrayResize(List, nElements);
59.             List[nElements - 1] = arg;
60. 
61.             return true;
62. 
63.         }
64.     //+----------------+
65.         T SearchKey(const uint arg)
66.         {
67.             for (uint c = 1; c < nElements; c++)
68.                 if (List[c].GetKey() == arg)
69.                     return List[c];
70. 
71.             return List[0];
72.         }
73.     //+----------------+
74. };
75. //+------------------------------------------------------------------+

Código 09

E para que o código 08 continue funcionando. Agora precisamos atualizar ele para o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. #define PrintX(X) Print(#X, " => [", X, "]")
07. //+------------------------------------------------------------------+
08. void OnStart(void)
09. {
10.     const string Names[] = 
11.         {
12.             "Daniel Jose",
13.             "Edimarcos Alcantra",
14.             "Carlos Almeida",
15.             "Yara Alves"
16.         };
17. 
18.     st_List <st_Dev01> list;
19. 
20.     for (uint c = 0; c < Names.Size(); c++)
21.     {
22.         st_Dev01 info;
23.         
24.         info.SetKeyInfo(c, Names[c]);
25.         list.AddList(info);
26.     }
27. 
28.     PrintX(list.SearchKey(2).GetInfo());
29. }
30. //+------------------------------------------------------------------+

Código 10

Observe que neste código 10, mudamos apenas e somente a linha 18. Isto comparando com o que era originalmente encontrado no código 08.

Perfeito. Agora temos uma pequena sobrecarga, com relação ao tipo de lista que podemos criar. Visto que este tipo de coisa, é exatamente o que mostramos recentemente nos artigos. Não vejo motivo para pânico. Assim o próximo passo é um pouco mais complicado de entender. Porém, como não existe uma forma simples de colocar o que será feito, como sendo um passo a passo. Vamos ter que ver isto em um único golpe. Ou melhor, em dois golpes. Um primeiro golpe será dado no arquivo de cabeçalho, enquanto o segundo golpe será feito no arquivo principal. Então não se assuste, meu caro leitor. Apenas procure não se distrair, para conseguir entender o que estará sendo feito.

Primeiro o arquivo de cabeçalho. Este é visto agora no código mostrado na sequência.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. template <typename KEY>
05. struct st_Base
06. {
07.     private :
08.         KEY KeyValue;
09.     public  :
10.     //+----------------+
11.         void SetKey(const KEY arg)
12.         {
13.             KeyValue = arg;
14.         }
15.     //+----------------+
16.         KEY GetKey(void)
17.         {
18.             return KeyValue;
19.         }
20.     //+----------------+
21. };
22. //+------------------------------------------------------------------+
23. template <typename KEY>
24. struct st_Dev01 : public st_Base <KEY>
25. {
26.     private :
27.         string ValueInfo;
28.     public  :
29.     //+----------------+
30.         void SetKeyInfo(KEY arg1, string arg2)
31.         {
32.             SetKey(arg1);
33.             ValueInfo = arg2;
34.         }
35.     //+----------------+
36.         string GetInfo(void)
37.         {
38.             return ValueInfo;
39.         }
40.     //+----------------+
41. };
42. //+------------------------------------------------------------------+
43. template <typename T, typename KEY>
44. struct st_List
45. {
46.     private :
47.         T    List[];
48.         uint nElements;
49.     public  :
50.     //+----------------+
51.         void Clear(void)
52.         {
53.             ArrayFree(List);
54.             nElements = 0;
55.         }
56.     //+----------------+
57.         bool AddList(const T &arg)
58.         {
59.             nElements += (nElements == 0 ? 2 : 1);
60.             ArrayResize(List, nElements);
61.             List[nElements - 1] = arg;
62. 
63.             return true;
64. 
65.         }
66.     //+----------------+
67.         T SearchKey(const KEY arg)
68.         {
69.             for (uint c = 1; c < nElements; c++)
70.                 if (List[c].GetKey() == arg)
71.                     return List[c];
72. 
73.             return List[0];
74.         }
75.     //+----------------+
76. };
77. //+------------------------------------------------------------------+

Código 11

Observe o que aconteceu no arquivo de cabeçalho que pode ser visto neste código 11, e compare ele com os arquivos anteriores vistos neste artigo. Você irá notar que este código 11 é bem mais interessante e divertido do que era os códigos anteriores. Porém não precisa ficar assustado. Não tem motivo para isto. Pelo menos não da forma como venho explicando as coisas. Quando aprendi como fazer isto, a alguns anos atrás lá na linguagem C e C++, foi bem difícil. Já que era difícil encontrar alguém que me explicasse como isto funciona. Mas aqui você irá entender como tal coisa funciona meu caro leitor.

Observe o seguinte: Na linha quatro, temos uma sobrecarga que será feita pelo compilador. Isto devido justamente ao fato de que estamos definindo um template para um código estrutural. Como você, já deve saber, o compilador irá criar uma versão para cada tipo de dado que será criado, ou precise ser criado. Ok, esta é a parte fácil. Agora vem a parte confusa. Pelo menos para mim, quando tentei aprender como se cria isto.

Como st_Dev01, está herdando a estrutura st_Base. E esta estrutura st_Base, é um template. A estrutura st_Dev01, TAMBÉM E OBRIGATORIAMENTE deverá ser definida como sendo uma estrutura template. Ou seja, não importa o que você pense. O simples fato de uma estrutura de dados, herdar um template de estrutura de dados. Também obriga que esta estrutura que esteja herdando outra, também seja um template. Isto de fato, não é muito complicado. Já que tudo que precisamos fazer é definir a linha 23.

Porém, e é aqui onde mora a parte complicada, precisamos passar este tipo, que está sendo definido na linha 23, para a estrutura base. Ou seja, st_Base, precisa receber este valor que estará sendo definido no código posteriormente. Parece simples fazer isto. Mas acredite, apanhei durante muito tempo, até entender que precisava mudar a declaração da linha 22, vista no código 09, para o que você pode ver nesta linha 24, vista no código 11.

Vocês não têm noção do quanto apanhei até aprender a fazer isto. Já que na época, NINGUEM ensinava como fazer tal coisa. Naturalmente, você sempre imagina que precisaria definir o que é visto na linha 23, e logo depois definir o que é visto na linha 30. Mas sem corrigir esta definição vista na linha 24, o código definitivamente NÃO COMPILA, MAS NEM A PORRETE.

Agora, como nossa lista, irá estar utilizando uma estrutura, ou melhor dizendo, um tipo de dado, que será sobrecarregado, dependendo de cada caso específico. Precisamos também, modificar o código da declaração na estrutura st_List. Mas esta é fácil de resolver, já que apenas mudamos a linha 43, e logo depois ajustamos a linha 57. E pronto. Nosso arquivo de cabeçalho está quase que livre, leve e solto. A única coisa que ainda o está prendendo a um tipo de dado, é a declaração da linha 27. Mas depois iremos mudar isto. Agora vamos ver como ficou o arquivo principal. Este pode ser visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. #define PrintX(X) Print(#X, " => [", X, "]")
07. //+------------------------------------------------------------------+
08. void OnStart(void)
09. {
10.     #define def_TypeKey uint
11. 
12.     const string Names[] = 
13.         {
14.             "Daniel Jose",
15.             "Edimarcos Alcantra",
16.             "Carlos Almeida",
17.             "Yara Alves"
18.         };
19. 
20.     st_List <st_Dev01 <def_TypeKey>, def_TypeKey> list;
21. 
22.     for (uint c = 0; c < Names.Size(); c++)
23.     {
24.         st_Dev01 <def_TypeKey> info;
25. 
26.         info.SetKeyInfo(c, Names[c]);
27.         list.AddList(info);
28.     }
29. 
30.     PrintX(list.SearchKey(2).GetInfo());
31. 
32.     #undef def_TypeKey
33. }
34. //+------------------------------------------------------------------+

Código 12

Santa ignorância. Misericórdia, e que DEUS tenha piedade de todos nós. Este cara é completamente sem noção. Como pode vir e nos apresentar um código como este, que é visto logo acima. Você não tem amor por nós, meros leitores e que estamos iniciando na programação? Quer definitivamente matar todos nós, só de olharmos para seus códigos, malucos.

Calma, meu caro leitor. Calma. Este código 12, é tão, mas tão simples, que chega a ser quase sem graça. Apesar de ser bastante divertido. Mas preste atenção. Como precisamos repetir certas coisas em diversos pontos no código. Utilizo a diretiva da linha 10, para criar uma definição para mudança rápida e segura em todos os pontos do código. Mas, neste código 12, precisamos mudar apenas dois pontos nele. O primeiro é a linha 20. Veja e compare a declaração desta variável, com a declaração da mesma variável feita no código 10.

Como a sobrecarga, também afetará a estrutura de dados que estaremos criando. Precisamos também mudar a declaração da linha 24. Que é onde declaramos a estrutura que será armazenada na lista. Todo o resto do código permanece igual. Tanto que isto é verdade, que a saída será a mesma mostrada na imagem 05.

Porém, ainda não terminamos este tópico. Como ainda temos espaço, para mostra mais uma melhoria. Vamos fazer ela agora. E está tornará a lista estrutural, quase perfeita. Digo quase, pois existe um pequeno problema, que não é possível resolver sem fazer uso de classes, ou mais conhecida como programação orientada em objetos. Mas isto será visto futuramente. Onde irei mostrar que problema é este, e como a programação orientada em objetos corrige o mesmo.

De qualquer forma, respire fundo, pois vamos mergulhar ainda mais fundo. Então voltando ao código do arquivo de cabeçalho. Iremos modificar o mesmo novamente, para o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. template <typename KEY>
05. struct st_Base
06. {
07.     private :
08.         KEY KeyValue;
09.     public  :
10.     //+----------------+
11.         void SetKey(const KEY arg)
12.         {
13.             KeyValue = arg;
14.         }
15.     //+----------------+
16.         KEY GetKey(void)
17.         {
18.             return KeyValue;
19.         }
20.     //+----------------+
21. };
22. //+------------------------------------------------------------------+
23. template <typename KEY, typename INFO>
24. struct st_Dev01 : public st_Base <KEY>
25. {
26.     private :
27.         INFO ValueInfo;
28.     public  :
29.     //+----------------+
30.         void SetKeyInfo(KEY arg1, INFO arg2)
31.         {
32.             SetKey(arg1);
33.             ValueInfo = arg2;
34.         }
35.     //+----------------+
36.         INFO GetInfo(void)
37.         {
38.             return ValueInfo;
39.         }
40.     //+----------------+
41. };
42. //+------------------------------------------------------------------+
43. template <typename T, typename KEY>
44. struct st_List
45. {
46.     private :
47.         T    List[];
48.         uint nElements;
49.     public  :
50.     //+----------------+
51.         void Clear(void)
52.         {
53.             ArrayFree(List);
54.             nElements = 0;
55.         }
56.     //+----------------+
57.         bool AddList(const T &arg)
58.         {
59.             nElements += (nElements == 0 ? 2 : 1);
60.             ArrayResize(List, nElements);
61.             List[nElements - 1] = arg;
62. 
63.             return true;
64. 
65.         }
66.     //+----------------+
67.         T SearchKey(const KEY arg)
68.         {
69.             for (uint c = 1; c < nElements; c++)
70.                 if (List[c].GetKey() == arg)
71.                     return List[c];
72. 
73.             return List[0];
74.         }
75.     //+----------------+
76. };
77. //+------------------------------------------------------------------+

Código 13

Note que a única coisa que mudei aqui, neste código 13, foi a linha 23. Somente isto. Agora podemos usar qualquer tipo de dado como chave, e também qualquer tipo de dado como sendo informação ligada a chave. Entendendo isto, podemos ver agora como ficou o código principal. Isto é mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. #define PrintX(X) Print(#X, " => [", X, "]")
07. //+------------------------------------------------------------------+
08. void OnStart(void)
09. {
10.     #define def_TypeKey     string
11.     #define def_TypeInfo    string
12. 
13.     const string Names[][2] = 
14.         {
15.             "Daniel Jose"       , "Chief Programmer",
16.             "Edimarcos Alcantra", "Programmer",
17.             "Carlos Almeida"    , "Junior Programmer",
18.             "Yara Alves"        , "Accounting"
19.         };
20. 
21.     st_List <st_Dev01 <def_TypeKey, def_TypeInfo>, def_TypeKey> list;
22. 
23.     for (int c = 0; c < ArrayRange(Names, 0); c++)
24.     {
25.         st_Dev01 <def_TypeKey, def_TypeInfo> info;
26. 
27.         info.SetKeyInfo(Names[c][1], Names[c][0]);
28.         list.AddList(info);
29.     }
30. 
31.     PrintX(list.SearchKey("Chief Programmer").GetInfo());
32.     PrintX(list.SearchKey("Guest").GetInfo());
33.     
34.     #undef def_TypeKey
35.     #undef def_TypeInfo
36. }
37. //+------------------------------------------------------------------+

Código 14

Note que o código em si não mudou quase que absolutamente nada. Porém, toda via e, entretanto, estas poucas diferenças que aconteceram aqui, são o suficiente para que tenhamos um código extremamente simples de ser utilizado e com resultados muito interessantes. Tanto pelo ponto de vista prático, quanto também pelo ponto de vista das possibilidades. Como as mudanças aqui, são muito simples de entender, vou dar a você, meu caro leitor, a oportunidade de tentar entender como este código funciona. Só que de qualquer forma, irei mostrar o resultado que ele apresenta. E isto é visto na imagem logo abaixo.

Imagem 06

Que coisa mais linda. Esta imagem 06 é um verdadeiro tesão. Já que mostra como as coisas aparentemente complicadas podem ser tornar super simples. Desde que você procure estudar e praticar o que está sendo mostrado nos artigos.


Considerações finais

Este com toda a certeza, é um artigo, que você deverá dedicar diversos minutos a fim de entender como, por que as coisas mostradas aqui funcionam. Isto pelo simples fato de que, tudo que foi visto e mostrado aqui, é originalmente direcionado ao que seria uma programação orientada em objetos. E muitos consideram ser pouco provável, criar algo que só é divulgado como sendo um tipo de programação. Mas que na verdade, tem como base e princípios uma programação completamente estrutural.

Como eu disse, antes de explicar o que seria a programação orientada em objetos. Iriamos navegar e mergulhar no que seria a base de origem de tal modelo de programação. Visto que a programação orientada em objetos, somente surgiu, devido a uma dificuldade em se fazer algo, na programação estrutural. Mas muito do que é dito como sendo exclusividade da programação orientada em objetos. Não é feita nela. Mas sim na programação estrutural.

Então meu caro leitor, procure praticar e estudar cada ponto que tem sido mostrado nestes artigos. Utilize os códigos do anexo, como meio de conseguir aprender e entender de forma correta, como realmente programar. E no próximo artigo, a diversão irá continuar. Então nos vemos em breve.

Arquivos anexados |
Anexo.zip (2.52 KB)
Funcionalidades do Assistente MQL5 que você precisa conhecer (Parte 39): Índice de força relativa Funcionalidades do Assistente MQL5 que você precisa conhecer (Parte 39): Índice de força relativa
O RSI é um oscilador de momentum popular que mede o ritmo e a magnitude da recente variação no preço de um título financeiro, para avaliar situações de sobrecompra ou sobrevenda. Entender a velocidade e a escala é essencial para identificar pontos de reversão. Aplicaremos esse oscilador em mais uma classe personalizada de sinais e examinaremos algumas de suas características. No entanto, começaremos resumindo nossa discussão sobre as bandas de Bollinger.
Simulação de mercado (Parte 19): Iniciando o SQL (II) Simulação de mercado (Parte 19): Iniciando o SQL (II)
Como eu disse no primeiro artigo sobre SQL, não faz sentido você perder tempo, programado rotinas e mais rotinas a fim de conseguir, gerar ou produzir algo que o próprio SQL já contém. Porém sem saber o básico do básico, você não conseguirá fazer nada em SQL, a fim de aproveitar de alguma forma o que esta ferramenta tem a nos oferecer. Sendo assim, aqui neste artigo iremos ver como fazer para conseguir executar tarefas primordiais a serem feitas em bancos de dados.
Simulação de mercado (Parte 20): Iniciando o SQL (III) Simulação de mercado (Parte 20): Iniciando o SQL (III)
Apesar de podermos fazer as coisas com um banco de dados, tendo cerca de 10 ou pouco mais registros. A coisa realmente se torna melhor assimilada, quando usamos um arquivo de banco de dados que contenha mais de 15 mil registros. Ou seja, se você for criar isto manualmente irá ser uma bela de uma tarefa. No entanto, dificilmente você irá encontrar algum banco de dados, mesmo para fins didáticos disponível para download. Mas não precisamos de fato recorrer a este tipo de coisa. Podemos usar o MetaTrader 5, para criar um banco de dados para nos. Neste artigo veremos como fazer isto.
Do básico ao intermediário: Estruturas (VII) Do básico ao intermediário: Estruturas (VII)
Neste artigo, será mostrado como podemos lidar com problemas de forma a estruturar as coisas, a fim de criar uma solução mais fácil e atrativa. Apesar do conteúdo ser voltado para a didática, não representando assim um código real. Os conceitos e conhecimento vistos aqui, precisam de fato ser muito bem assimilados. Isto para que no futuro, você consiga acompanhar os códigos que iremos mostrar.