This shows you the differences between two versions of the page.
| 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]] | ||