User Tools

Site Tools


cpp:syntax:class:generic

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
cpp:syntax:class:generic [2021/04/06 14:47]
bmonsuez created
cpp:syntax:class:generic [2022/11/18 10:47] (current)
Line 6: Line 6:
  
 <code cpp> <code cpp>
 +#​include<​algorithm>​
 +
 class buffer class buffer
 { {
Line 24: Line 26:
   }   }
  
-  operator uint8_t*() const { return m_buffer; }+  operator ​const uint8_t*() const { return m_buffer; } 
 +  operator uint8_t*() { return m_buffer; } 
 +  ​
   uint8_t operator[](int anIndex) const    uint8_t operator[](int anIndex) const 
   {    { 
Line 40: Line 44:
 </​code>​ </​code>​
  
-Cette classe définit un buffer d'une taille de 128 octets.+Cette classe définit un buffer d'une taille de 128 octets. ​Elle redéfinit les opérateurs suivant :  
 +  * ''​operator[]''​ qui permet d'​accéder en lecture et en écriture au buffer interne natif. 
 +  * ''​operator uint8_t*()''​ qui permet de récupérer un pointeur autorisant la lecture ou l'​écriture dans le buffer vu. 
 +  * ''​operator =(const buffer&​)''​ et ''​buffer(const buffer&​)''​ correspondant à l'​opérateur de recopie. 
 + 
 + 
 +Nous voyons que si nous souhaitons faire un buffer d'une taille différente,​ nous devons définir une nouvelle classe dont la seule différence est la taille du buffer. 
 + 
 +De même si nous souhaitons faire un buffer qui va stocker des éléments de base autres que des entiers 8 bits, par exemple des entiers 64 bits, il est nécessaire de réécrire une nouvelle classe en remplaçant ''​uint8_t''​ par un type différent. 
 + 
 +===== Paramétriser une classe par un type ===== 
 + 
 +Dans un premier temps, nous allons paramétriser la classe ''​buffer''​ par le type des éléments qui sont contenus dans le ''​buffer''​.  
 + 
 +Pour ce faire, nous allons déclarer la classe ''​buffer''​ comme étant un modéle de classe à l'​instar des [[cpp:​syntax:​functions:​template|modèles de fonctions]]. 
 + 
 +<code cpp> 
 +#​include<​algorithm>​ 
 + 
 +template<​class itemT> 
 +class buffer 
 +
 +private: ​  
 +  itemT m_buffer[128];​ 
 + 
 +public: ​  
 + 
 +  buffer(const buffer<​itemT>&​ anotherBuffer) 
 +  { 
 +    std::​copy(anotherBuffer.m_buffer,​ anotherBuffer.m_buffer + 128, m_buffer);​ 
 +  } 
 +  int size() const { return 128; } 
 +  buffer& operator = (const buffer<​itemT>&​ anotherBuffer) 
 +  { 
 +    std::​copy(anotherBuffer.m_buffer,​ anotherBuffer.m_buffer + 128, m_buffer);​ 
 +    return this;  
 +  } 
 + 
 +  operator const itemT*() const { return m_buffer; } 
 +  operator itemT*() { return m_buffer; } 
 +   
 +  itemT operator[](int anIndex) const  
 +  {  
 +      if(anIndex >= 128) 
 +          throw std::​out_of_range("​index larger than buffer"​);​ 
 +      return m_buffer[anIndex];​ 
 +  } 
 +  itemT& operator[](int anIndex) 
 +  {  
 +      if(anIndex >= 128) 
 +          throw std::​out_of_range("​index larger than buffer"​);​ 
 +      return m_buffer[anIndex];​ 
 +  } 
 +}; 
 + 
 +</​code>​ 
 + 
 +La déclaration de la classe comme un modèle de classe s'​effectue par : 
 + 
 +<code cpp> 
 +template<​class itemT> 
 +class buffer 
 +</​code>​ 
 + 
 +qui indique que la classe est un __template__ qui a un type paramètre qui est le type des éléments stockés dans le buffer, soit le type ''​itemT''​.  
 + 
 +Désormais, pour utiliser la classe ''​buffer'',​ il est nécessaire de spécifier le type de ses éléments. Ainsi, quand je souhaite créer un buffer de caractères,​ il suffit d'​écrire ''​buffer<​char>'':​ 
 + 
 +<code cpp> 
 + 
 +void funct() 
 +
 +    buffer<​char>​ bufferOfCharacters;​ 
 +    bufferOfCharacters[0] = '​t';​ 
 +    bufferOfCharacters[1] = '​e';​ 
 +    bufferOfCharacters[2] = '​s';​ 
 +    bufferOfCharacters[3] = '​t';​ 
 +    std::string token((const char*)bufferOfCharacters,​ (const char*)bufferOfCharacters + 4); 
 +    std::cout << token << std::​endl;​ 
 +
 +</​code>​ 
 + 
 +Cette fonction crée un buffer de 128 caractères dénommé ''​bufferOfCharacters'',​ stocke dans le buffer les caractères '​t',​ '​e',​ '​s',​ '​t',​ copie ces 4 caractères dans un objet ''​string''​ et affiche le contenu de l'​objet ''​string''​ sur la console. 
 + 
 +Il est possible de paramétrer des classes avec plus d'un type. Par exemple, la déclaration de la classe [[https://​en.cppreference.com/​w/​cpp/​string/​basic_string|std::​basic_string]] de la STL définit trois paramètres de type ''​charT'',​ ''​traits''​ et ''​allocator''​ comme suit : 
 + 
 +<code cpp> 
 +template<​ 
 +    class charT, 
 +    class traits = std::​char_traits<​charT>,​ 
 +    class allocator = std::​allocator<​charT>​ 
 +    class basic_string;​ 
 +</​code> ​    
 + 
 +Il est intéressant de constater qu'il est possible de définir un paramètre de type par défaut. Ainsi, écrire : 
 + 
 +<code cpp> 
 +    std::​basic_string<​char>​ myString; 
 +</​code>​ 
 + 
 +est équivalent à écrire : 
 + 
 +<code cpp> 
 +    std::​basic_string<​char,​ std::​char_traits,​ std::​allocator<​charT>>​ myString; 
 +</​code>​ 
 + 
 +Si nous ne spécifions pas les types ''​traits''​ et ''​allocator'',​ le compilateur utilise les types par défaut. 
 + 
 + 
 +===== Paramétriser une classe par une valeur ===== 
 + 
 +Nous souhaitons pouvoir choisir la taille du buffer. Pour ce faire, nous allons définir un modèle de classe qui est paramétrisé par la taille que nous souhaitons allouer au buffer.  
 + 
 + 
 +<code cpp> 
 +#​include<​algorithm>​ 
 + 
 +template<​class itemT, int bufferSize = 128> 
 +class buffer 
 +
 +private: ​  
 +  itemT m_buffer[bufferSize];​ 
 + 
 +public: ​  
 + 
 +  buffer(const buffer<​itemT,​ bufferSize>&​ anotherBuffer) 
 +  { 
 +    std::​copy(anotherBuffer.m_buffer,​ anotherBuffer.m_buffer + bufferSize, m_buffer);​ 
 +  } 
 +  int size() const { return bufferSize; } 
 +  buffer& operator = (const buffer<​itemT,​ bufferSize>&​ anotherBuffer) 
 +  { 
 +    std::​copy(anotherBuffer.m_buffer,​ anotherBuffer.m_buffer + bufferSize, m_buffer);​ 
 +    return this;  
 +  } 
 + 
 +  operator const itemT*() const { return m_buffer; } 
 +  operator itemT*() { return m_buffer; } 
 +   
 +  itemT operator[](int anIndex) const  
 +  {  
 +      if(anIndex >= bufferSize) 
 +          throw std::​out_of_range("​index larger than buffer"​);​ 
 +      return m_buffer[anIndex];​ 
 +  } 
 +  itemT& operator[](int anIndex) 
 +  {  
 +      if(anIndex >= bufferSize) 
 +          throw std::​out_of_range("​index larger than buffer"​);​ 
 +      return m_buffer[anIndex];​ 
 +  } 
 +}; 
 + 
 +</​code>​ 
 + 
 +Désormais, quand nous créons un buffer, nous pouvons spécifier la taille du buffer. 
 + 
 +<code cpp> 
 +buffer<​int,​ 64> bufferOfIntegers; ​  // buffer contenant 64 entiers. 
 +buffer<​char,​ 32> bufferOfChars; ​    // buffer contenant 32 caractères. 
 +buffer<​float>​ bufferOfFloats; ​      // buffer contenant 128 (la valeur par défaut) nombres à virgule flottante. 
 +</​code>​
  
 +===== Pour aller plus loin =====
  
 +[[https://​en.cppreference.com/​w/​cpp/​language/​class_template|Template class]]
  
 +[[https://​en.cppreference.com/​w/​cpp/​language/​template_parameters|Template parameters and template arguments]]
  
 +[[https://​en.cppreference.com/​w/​cpp/​language/​template_argument_deduction|Template argument deduction]]
  
 +[[https://​en.cppreference.com/​w/​cpp/​language/​constraints|Contraints & Concepts]]
  
cpp/syntax/class/generic.1617720477.txt.gz · Last modified: 2021/04/06 14:47 by bmonsuez