
FAQ C++Consultez toutes les FAQ
Nombre d'auteurs : 34, nombre de questions : 368, derni�re mise � jour : 14 novembre 2021 Ajouter une question
Cette FAQ a �t� r�alis�e � partir des questions fr�quemment pos�es sur les forums de http://www.developpez.com et de l'exp�rience personnelle des auteurs.
Je tiens � souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne pr�tend pas non plus �tre compl�te. Si vous trouvez une erreur ou si vous souhaitez devenir r�dacteur, lisez ceci.
Sur ce, nous vous souhaitons une bonne lecture.
- Quels sont les enjeux associ�s aux techniques Orient�es Objets ?
- Qu'est-ce qu'un objet ?
- Qu'est-ce que l'h�ritage ?
- Qu'est-ce que l'encapsulation ?
- L'encapsulation constitue-t-elle un m�canisme de s�curit� ?
- Comment le C++ permet-il d'am�liorer le compromis entre fiabilit� et simplicit� d'utilisation ?
- Comment savoir si je dois d�river une classe ou l'encapsuler ?
- Qu'est-ce qu'une bonne interface ?
- Que sont les accesseurs / mutateurs ?
- Quand et comment faut-il utiliser des accesseurs / mutateurs ?
- La conception d'une classe doit-elle se faire plut�t par l'ext�rieur ou par l'int�rieur ?
- Qu'est-ce que le polymorphisme ?
- Qu'est-ce que la coercition ?
- Qu'est-ce que le polymorphisme param�trique ?
- Qu'est-ce que le polymorphisme d'inclusion ?
- Qu'est-ce qui est entendu par � param�trer un comportement � ?
- Comment varier le comportement au moment de l'ex�cution par le polymorphisme d'inclusion ?
- Comment varier le comportement au moment de l'�criture de code (template) ?
- Comment varier le comportement � la compilation par les directives du pr�processeur ?
- Comment varier le comportement � l'�dition des liens ?
- Comment varier le comportement � l'ex�cution par le chargement dynamique de biblioth�que ?
- Comment varier le comportement au moment de l'ex�cution par agr�gation ?
- Comment choisir entre les diff�rents types de param�trage de comportement ?
Les techniques OO sont la meilleure fa�on connue de d�velopper de grosses applications ou des syst�mes complexes.
L'industrie du logiciel n'arrive pas � satisfaire les demandes pour des syst�mes logiciels aussi imposants que complexes, mais cet �chec est d� � nos succ�s : nos r�ussites ont habitu� les utilisateurs � toujours en demander plus. Malheureusement, nous avons ainsi cr�� une demande du march� que les techniques 'classiques' de programmation ne pouvaient satisfaire. Cela nous a oblig� � cr�er un meilleur paradigme.
Le C++ permet de programmer OO, mais il peut aussi �tre utilis� comme un langage classique (� un C am�lior� �). Si vous comptez l'utiliser de cette fa�on, n'esp�rez pas profiter des b�n�fices apport�s par la programmation OO.
Une zone de stockage avec une s�mantique associ�e.
Apr�s la d�claration suivante,
Code c++ : | S�lectionner tout |
int i;
L'h�ritage consiste � construire une classe (appel�e classe fille) par sp�cialisation d'une autre classe (classe m�re). On peut illustrer ce principe en prenant l'exemple des mammif�res (classe m�re) et l'homme d'un c�t� (classe fille1) et les chiens (classe fille2). En effet, les chiens et les hommes sont tous deux des mammif�res mais ont des sp�cificit�s.
Il s'agit d'�viter des acc�s non autoris�s � certaines informations et/ou fonctionnalit�s.
L'id�e cl� est de s�parer la partie volatile de la partie stable. L'encapsulation permet de dresser un mur autour d'une partie du code, ce qui permet d'emp�cher une autre partie d'acc�der � cette partie dite volatile ; les autres parties du code ne peuvent acc�der qu'� la partie stable. Cela �vite que le reste du code ne fonctionne plus correctement lorsque le code volatile est chang�. Dans le cadre de la programmation objet, ces parties de code sont normalement une classe ou un petit groupe de classe.
Les � parties volatiles � sont les d�tails d'impl�mentation. Si le morceau de code est une seule classe, la partie volatile est habituellement encapsul�e en utilisant les mots-cl�s private et protected. S'il s'agit d'un petit groupe de classe, l'encapsulation peut �tre utilis�e pour interdire � des classes enti�res de ce groupe. L'h�ritage peut aussi �tre utilis� comme une forme d'encapsulation.
Les parties stables sont les interfaces. Une bonne interface procure une vue simplifi�e exprim�e dans le vocabulaire de l'utilisateur, et est cr��e dans l'optique du client. (un utilisateur, dans le cas pr�sent, signifie un autre d�veloppeur, non pas le client qui ach�tera l'application). Si le morceau de code est une classe unique, l'interface est simplement l'ensemble de ses membres publics et des fonctions amies. S'il s'agit d'un groupe de classes, l'interface peut inclure un certain nombre de classes.
Concevoir une interface propre et s�parer cette interface de son impl�mentation permet aux utilisateurs de l'utiliser convenablement. Mais encapsuler (mettre dans une capsule) l'impl�mentation force l'utilisateur � utiliser l'interface.
Non.
L'encapsulation ne constitue pas un m�canisme de s�curit�. Il s'agit d'une protection contre les erreurs, pas contre l'espionnage.
En g�n�ralisant le concept d'encapsulation.
Chaque classe ne propose � son utilisateur qu'un nombre minimal de fonctions publiques tr�s sp�cifiques et dont le comportement est clairement d�termin�. Chaque fonction publique fournie par une classe correspond � un service que l'on attend d'elle.
Ces fonctions d�finissent ce que l'on appelle l'interface de la classe en question.
Le r�sultat final est comme une � structure encapsul�e �. Cela am�liore le compromis entre fiabilit� (dissimulation de l'information) et facilit� d'utilisation (les instances multiples).
J'applique une m�thode simple : la question � se poser est la suivante : est-ce que X est un genre de Y, ou est-ce que X utilise un Y ?
Si la r�ponse est X est un genre de Y, il s'agit d'un cas o� je d�rive une classe.
Si la r�ponse est X utilise Y, il s'agit d'un cas o� je vais encapsuler une classe.
Quand elle pr�sente une vue simplifi�e d'un bout de logiciel, et est exprim�e dans les termes de l'utilisateur (le bout de logiciel correspond habituellement � une classe ou un petit groupe de classes et l'utilisateur est un autre d�veloppeur, non le client final).
� Vue simplifi�e � signifie que les d�tails sont intentionnellement cach�s. Cela r�duit donc le risque d'erreur lors de l'utilisation de la classe.
� Vocabulaire de l'utilisateur � veut dire que l'utilisateur n'a pas besoin d'apprendre de nouveaux mots ou concepts. Cela r�duit donc la courbe d'apprentissage de l'utilisateur.
Un accesseur (accessor en anglais) est une fonction membre renvoyant la valeur d'une propri�t� d'un objet. Un mutateur (mutator en anglais) ou encore modifieur (modifier en anglais) est une fonction membre qui modifie la valeur d'une propri�t� d'un objet.
L'utilisation d'accesseurs / mutateurs permet de masquer l'impl�mentation des donn�es de la classe (encapsulation) et de faire �voluer celle-ci sans contraintes pour l'utilisateur final. Si ce dernier est oblig� de passer par des accesseurs / mutateurs au lieu d'acc�der directement aux donn�es internes, ces derni�res peuvent �tre chang�es � tout moment et il suffit alors d'adapter le code des accesseurs / mutateurs. Le code qui utilisait l'ancienne classe peut utiliser la nouvelle sans s'apercevoir des changements effectu�s, alors qu'un acc�s direct aux donn�es internes aurait n�cessit� de tout reprendre.
Les accesseurs / mutateurs permettent donc de s�parer l'utilisation des donn�es de leur impl�mentation, en plus de pouvoir effectuer des traitements ou des contr�les annexes lors de l'assignation des membres.
Dans l'exemple suivant :
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Person { public: // accesseur : renvoie le nom const std::string & GetName() const // notez le const { return name; } // mutateur : change le nom void SetName( const std::string & NewName ) { name = NewName; } private: std::string name; // nom de la personne }; |
Comme le montre cet exemple, il est courant de pr�fixer le nom des accesseurs / mutateurs respectivement par Get / Set. Pour cette raison, on appelle aussi les accesseurs / mutateurs des getter / setter.
Les accesseurs ne modifiant pas l'objet mais se contentant de fournir un acc�s (d'o� leur nom) en lecture seule sur une de ses propri�t�s, c'est une bonne pratique que de rendre une telle fonction membre constante comme cela est le cas ici pour GetName (lire � ce sujet

Un point important est que les accesseurs / mutateurs ne s'appliquent pas forc�ment sur des donn�es membres existantes d'une classe, mais peuvent �tre utilis�s pour simuler l'existence d'une propri�t� qui n'est pas directement stock�es en interne dans la classe. Lire � ce sujet

Parmi les fonctions publiques d'une classe, certaines miment la pr�sence d'une donn�e membre. On nomme aussi de telles fonctions des accesseurs. Il n'y a pas forc�ment de relation un-pour-un entre un accesseur et une donn�e membre (comme cela est le cas pour l'accesseur GetName et la variable name dans l'exemple de la question Que sont les accesseurs / mutateurs ?. Une donn�e encapsul�e ne doit pas forcement �tre expos�e via � un accesseur. L'�tat interne d'un objet est� interne, et doit le rester.
Il faut distinguer deux choses lorsque l'on �crit une classe : son interface et son impl�mentation. Le but des accesseurs / mutateurs est d'effectuer le lien entre les deux, lien qui n'a pas � �tre direct. L'interface, qui sera visible du reste du monde et qui est donc la premi�re chose � d�terminer quand on �crit une classe, expose un certain nombre de propri�t�s, qui peuvent ou non �tre directement stock�es dans la classe. Ce dernier point est un d�tail d'impl�mentation qui n'a pas � �tre connu, et c'est le r�le des accesseurs / mutateurs de le masquer.
Prenons l'exemple d'une classe qui permet de conna�tre l'�ge d'un individu :
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | #include "date.h" // classe permettant de stocker une date (pour l'exemple) class Person { public: // �ge de la personne int GetAge() const; private: // date de naissance Date date_of_birth; }; |
Cet exemple illustre bien le fait qu'un accesseur exporte une propri�t� qui n'a nullement l'obligation d'exister de mani�re explicite dans la classe. De m�me, une variable membre ne doit pas forc�ment �tre export�e via un accesseur, comme dans cet exemple avec la date de naissance.
Un autre exemple typique est celui de la classe Temperature qui permet de manipuler des temp�ratures en degr�s Celsius ou Fahrenheit :
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Temperature { public: // degr�s Celsius double GetCelsius() const { return this->temp_celsius; } void SetCelsius( double NewTemp ) { this->temp_celsius = NewTemp; } // degr�s Fahrenheit double GetFahrenheit() const { return ( ( this->temp_celsius * 9.0 ) / 5.0 ) + 32.0; } void SetFahrenheit( double NewTemp ) { this->temp_celsius = ( NewTemp - 32.0 ) * 5.0 / 9.0; } private: // en interne, on stocke en degr�s Celsius double temp_celsius; }; |
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Temperature { public: // degr�s Celsius double GetCelsius() const { return ( this->temp_fahrenheit - 32.0 ) * 5.0 / 9.0; } void SetCelsius( double NewTemp ) { this->temp_fahrenheit = ( ( NewTemp * 9.0 ) / 5.0 ) + 32.0; } // degr�s Fahrenheit double GetFahrenheit() const { return this->temp_fahrenheit; } void SetFahrenheit( double NewTemp ) { this->temp_fahrenheit = NewTemp; } private: // en interne, on stocke en degr�s Fahrenheit double temp_fahrenheit; }; |
Vous l'aurez compris : le choix de d�finir des accesseurs / mutateurs doit �tre en accord avec la conception et l'analyse du probl�me. Il ne faut pas syst�matiser leur d�finition pour toutes les donn�es membres d'une classe.
Par l'ext�rieur !
Une bonne interface fournit une vue simplifi�e exprim�e dans le vocabulaire de l'utilisateur. Dans le cas de la programmation par objets, une interface est g�n�ralement repr�sent�e par une classe unique ou par un groupe de classes tr�s proches.
R�fl�chissez d'abord � ce qu'un objet de la classe est du point de vue logique, plut�t que de r�fl�chir � la fa�on dont vous allez le repr�senter physiquement. Imaginez par exemple que vous ayez une classe Stack (une pile) et que vous vouliez que son impl�mentation utilise une LinkedList (une liste cha�n�e)
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 | class Stack { public: // ... private: LinkedList list_; }; |
Voyons maintenant un cas un peu plus subtil. Supposez que l'impl�mentation de la classe LinkedList soit bas�e sur une liste cha�n�e d'objets Node (nouds), et que chaque Node ait un pointeur sur le Node suivant :
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | class Node { /*...*/ }; class LinkedList { public: // ... private: Node* first_; }; |
Une r�ponse parmi d'autres : une LinkedList n'est pas une cha�ne d'objets Nodes. C'est peut-�tre bien comme �a qu'elle est impl�ment�e, mais ce n'est pas ce qu'elle est. Ce qu'elle est, c'est une suite d'�l�ments. L'abstraction LinkedList doit donc �tre fournie avec une classe � LinkedListIterator �, et c'est cette classe � LinkedListIterator � qui doit disposer d'un operator++ permettant de passer � l'�l�ment suivant, ainsi que de fonctions get()/set() donnant acc�s � la valeur stock�e dans un Node (la valeur stock�e dans un Node est sous l'unique responsabilit� de l'utilisateur de la LinkedList, c'est pourquoi il faut des fonctions get()/set() permettant � cet utilisateur de la manipuler comme il l'entend).
Toujours du point de vue de l'utilisateur, il pourrait �tre souhaitable que la classe LinkedList offre un moyen d'acc�der � ses �l�ments qui mimique la fa�on dont on acc�de aux �l�ments d'un tableau en utilisant l'arithm�tique des pointeurs :
Code c++ : | S�lectionner tout |
1 2 3 4 5 | void userCode(LinkedList& a) { for (LinkedListIterator p = a.begin(); p != a.end(); ++p) cout << *p << '\n'; } |
Le code se trouve ci-dessous. L'id�e centrale est que la classe LinkedList n'a pas de fonction donnant acc�s aux Nodes. Les Nodes sont une technique d'impl�mentation, technique qui est compl�tement masqu�e. Les internes de la classe LinkedList pourraient tout � fait �tre remplac�s par une liste doublement cha�n�e, ou m�me par un tableau, avec pour seule diff�rence une modification au niveau de la performance des fonctions prepend(elem) et append(elem).
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <cassert> // Succ�dan� de gestion d'exceptions class LinkedListIterator; class LinkedList; class Node { // Pas de membres public, c'est une � classe priv�e � friend LinkedListIterator; // Une classe amie friend LinkedList; Node* next_; int elem_; }; class LinkedListIterator { public: bool operator== (LinkedListIterator i) const; bool operator!= (LinkedListIterator i) const; void operator++ (); // Aller � l'�l�ment suivant int& operator* (); // Acc�der � l'�l�ment courant private: LinkedListIterator(Node* p); Node* p_; }; class LinkedList { public: void append(int elem); // Ajoute elem apr�s le dernier �l�ment void prepend(int elem); // Ajoute elem avant le premier �l�ment // ... LinkedListIterator begin(); LinkedListIterator end(); // ... private: Node* first_; }; |
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | inline bool LinkedListIterator::operator== (LinkedListIterator i) const { return p_ == i.p_; } inline bool LinkedListIterator::operator!= (LinkedListIterator i) const { return p_ != i.p_; } inline void LinkedListIterator::operator++() { assert(p_ != NULL); // ou bien if (p_==NULL) throw ... p_ = p_->next_; } inline int& LinkedListIterator::operator*() { assert(p_ != NULL); // ou bien if (p_==NULL) throw ... return p_->elem_; } inline LinkedListIterator::LinkedListIterator(Node* p) : p_(p) { } inline LinkedListIterator LinkedList::begin() { return first_; } inline LinkedListIterator LinkedList::end() { return NULL; } |
Ainsi, les seules fonctions get()/set() pr�sentes sont l� pour permettre la modification des �l�ments de la liste cha�n�e, mais ne permettent absolument pas la modification des donn�es d'impl�mentation de la liste. Et la liste cha�n�e ayant compl�tement masqu� son impl�mentation, elle peut donner des garanties tr�s fortes concernant cette impl�mentation (dans le cas d'une liste doublement cha�n�e par exemple, la garantie pourrait �tre qu'il y a pour chaque pointeur avant, un pointeur arri�re dans le Node suivant).
Nous avons donc vu un exemple dans lequel les valeurs de certaines des donn�es d'une classe �taient sous la responsabilit� des utilisateurs de la classe (et la classe a besoin d'exposer des fonctions get()/set() pour ces donn�es) mais dans lequel les donn�es contr�l�es uniquement par la classe ne sont pas n�cessairement accessibles par des fonctions get()/set().
Note : le but de cet exemple n'�tait pas de vous montrer comment �crire une classe de liste cha�n�e. Et d'abord, vous ne devriez pas � pondre � votre propre classe liste, vous devriez plut�t utiliser l'une des classes de type � conteneur standard � fournie avec votre compilateur. La meilleure solution est d'utiliser l'une des classes conteneurs du standard C++, par exemple la classe template list<T>.
Le polymorphisme, c'est la capacit� d'une expression � �tre valide quand les valeurs pr�sentes ont des types diff�rents. On trouve diff�rents types de polymorphismes :
- ad-hoc�: surcharge et coercition ;
- universel (ou non ad-hoc)�: param�trique et d'inclusion.







Comme Mr Jourdain �crivait de la prose sans le savoir, vous avez certainement d�j� utilis� la coercition sans le savoir. Derri�re cette expression se cache tout simplement les m�canismes de conversion implicite :
Code c++ : | S�lectionner tout |
1 2 3 | int op1(1); double op2(2.1); double result = op1 + op2; // polymorphisme de coercition |
Une classe s'appuie sur la d�finition d'op�rateur de conversion pour pouvoir �tre utilis�e dans ce type de polymorphisme :
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include <iostream> class CMyClass { public: operator bool()const { return true; } }; int main() { CMyClass a; std::cout << std::boolalpha << a << std::endl; return 0; } |
Le polymorphisme param�trique passe par l'utilisation des techniques g�n�riques pour offrir un m�me service pour tout un ensemble de types :
Code c++ : | S�lectionner tout |
1 2 3 4 5 | template<class T> void dump(T var) { std::cout << Timestamp() << " : " << var << std::endl; } |
On parle parfois de polymorphisme contraint ou born� lorsqu'il s'agit d'introduire des contraintes sur les types avec lesquels une fonction ou une classe g�n�rique peut effectivement �tre instanci�e. Cela est possible avec le C++ en combinant les classes traits et des biblioth�ques comme std::enable_if ou static_assert. La notion de concept a pour but d'�tendre cette notion de contraintes. Un TS (technical specification, une sorte de version beta d'un standard) sur ce sujet a m�me �t� accept�.
Souvent r�sum� tout simplement (et trop hativement) � ��polymorphisme��, le polymorphisme d'inclusion s'appuie sur l'h�ritage public :
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | void function(IInterface const &var_) { var_.Action(); } class IInterface { // ... }; class CConcrete : public IInterface { // ... }; int main() { CConcrete c; Fonction(c); return 0; } |
Le polymorphisme d'inclusion doit faire sens avec l'h�ritage public. Il ne doit pas �tre utilis� uniquement pour b�n�ficier d'une surcharge.
Il s'agit simplement en fait d'introduire un point de variabilit� dans votre code, de faire en sorte que selon <on ne sait pas trop quoi>, le comportement de ce morceau de code soit diff�rent.
Le comportement d'un code C++ peut �tre param�tr� de diff�rentes fa�ons :
- pendant l'�criture du code : les templates ;
- � la compilation : surcharges, conversions implicites et directives de compilation ;
- � l'�dition des liens ;
- � l'ex�cution par le chargement dynamique de biblioth�que ;
- � l'ex�cution par le polymorphisme d'inclusion (fonctions virtuelles).









En C++, on utilise souvent l'h�ritage pour ce faire. En effet, imaginez que nous soyons en pr�sence d'une hi�rarchie de composants graphiques, dont la classe de base serait Widget. On aurait ainsi Button et Textfield qui h�riteraient de Widget par exemple. Enfin, chacun poss�derait une m�thode show() qui permet d'afficher le composant en question. Bien entendu, un Button et un Textfield �tant de natures diff�rentes, leur affichage le serait aussi.
C'est gr�ce au polymorphisme d'h�ritage, mis en ouvre en C++ gr�ce au mot cl� virtual, que l'on peut r�aliser cela dynamiquement : � l'ex�cution du programme, il sera choisi d'utiliser la m�thode Button::show() ou la m�thode Textfield::show() selon le type r�el de l'objet sur lequel on appelle show(). Voici un exemple minimal illustrant cela.
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class Widget { public: virtual ~Widget() { /* ... */ } void show() { // ... do_show(); // ... } // ... private : virtual void do_show()=0; // fonction virtuelle pure }; class Button : public Widget { private : virtual void do_show() { std::cout << "Button" << std::endl; } // ... }; class Textfield : public Widget { private : virtual void do_show() { std::cout << "Textfield" << std::endl; } // ... }; void show_widget(Widget& w) { w.show(); } // ... Button b; Textfield t; show_widget(b); // affiche "Button" show_widget(t); // affiche "Textfield" |
Imaginez que vous ayez con�u une classe qui encapsule un calcul tr�s lourd, au point que vous ayez mis sur pieds deux impl�mentations, l'une monothread�e, l'autre multithread�e. Il serait dommage de les faire h�riter d'une classe abstraite et d'en h�riter pour chacune des versions, induisant un co�t � cause de la virtualit�, qui est ici superflue. Vous avez une possibilit� qui vous permettra de tout g�rer � la compilation, en utilisant les templates. Nous allons illustrer avec une fonction qui mesure le temps pris par le calcul.
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | template <class Computation> void do_something() { std::time_t start = time(NULL); Computation::compute(); std::time_t end = time(NULL); std::cout << end - start << " seconds." << std::endl; } struct SingleThreadedComputation { static void compute() { // impl�mentation monothread } }; struct MultiThreadedComputation { static void compute() { // impl�mentation multithread } }; // par exemple : #ifdef STCOMPUTATION do_something<SingleThreadedComputation>(); #elif defined MTCOMPUTATION do_something<MultiThreadedComputation>(); #endif // comportement que l'on peut choisir soit avec un #define, // soit avec l'option de compilation -DSTCOMPUTATION ou -DMTCOMPUTATION |
Cette fa�on de faire s'approche de ce que l'on appelle le

C'est une sorte d'�quivalent du Design Pattern Strategy, � la sauce C++ et templates.
Ensuite vient le polymorphisme issu de la manipulation du pr�processeur de votre compilateur. En effet, en jouant avec les #ifdef, nous pouvons par exemple s�lectionner un certain code ou un autre selon des directives de compilation, qui permettent de modifier le comportement de l'application g�n�r�e, et ce au moment de compiler. Cela se base sur le sch�ma basique suivant (qui a �t� utilis� pour l'exemple de calcul mono|multithread) :
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 | #ifdef OPTION1 // code 1 #elif defined OPTION2 // code 2 #elif defined OPTION3 // code 3 #else // code 4 #endif |
Vous pouvez �galement obtenir du polymorphisme en jouant sur la liaison avec des biblioth�ques. A partir d'une m�me interface, vous pouvez avoir diff�rentes impl�mentations produisant des biblioth�ques statiques diff�rentes (.lib, .a�). La commande d'�dition des liens (ou dans votre makefile ou dans les options d'un projet avec un I.D.E.) pr�cise la biblioth�que avec laquelle les liens doivent �tre r�solus. L'ex�cutable g�n�r� fait alors appel � l'interface impl�ment�e dans la biblioth�que avec laquelle il a �t� li�e.
Une application peut choisir de varier son comportement en chargeant dynamiquement des biblioth�ques (.dll, .so�) et en allant chercher dans celles-ci l'impl�mentation de l'interface variable. Le comportement va alors changer selon la DLL propos�e � l'ex�cution du moment qu'elle respecte l'interface qu'attend le programme.
S'il est n�cessaire de pouvoir modifier le comportement d'un objet au cour de l'ex�cution, la solution la plus adapt�e est sans doute l'application du design pattern Strategy.
Le principe de ce patron de conception est de d�finir autant de classes que de comportements diff�rents. Toutes ces classes impl�mentent une m�me interface. La classe � param�trer poss�de une agr�gation vers un objet du type de l'interface.
Code c++ : | S�lectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | // Interface de comportement pour baladeur (utilisant le pattern NVI) class walkman_behaviour { public: virtual ~walkman_behaviour(){} void click_back_button() { do_click_back_button(); } void click_forward_button() { do_click_forward_button(); } private: virtual void do_click_back_button() = 0; virtual void do_click_forward_button() = 0; }; // Collection de comportements pour baladeur namespace walkman_behaviours { class mp3_reader: public walkman_behaviour { public: void do_click_back_button() { // Lire chanson pr�c�dente... } void do_click_forward_button() { // Lire chanson suivante... } }; class fm_tuner: public walkman_behaviour { public: void do_click_back_button() { // Passer � la fr�quence pr�c�dente... } void do_click_forward_button() { // Passer � la fr�quence suivante... } }; } //baladeur audio class walkman { public: walkman(walkman_behaviour& c): behaviour_(&c) { } void behaviour(walkman_behaviour& c) { behaviour_ = &c; } void click_back_button() { comportement_->click_back_button(); } void click_forward_button() { comportement_->click_forward_button(); } private: walkman_behaviour* behaviour_; }; int main() { walkman_behaviours::mp3_reader behave_mp3; walkman_behaviours::fm_tuner behave_fm; walkman b(behave_mp3); // Comportement par d�faut : lecteur mp3 b.click_forward_button(); // Lit la chanson suivante b.behaviour(behave_fm); // Changement de comportement b.click_back_button(); // Passe � la fr�quence pr�c�dente return 0; } |
Il faut d�sormais choisir celui qui convient au type de param�trage de comportement que vous voulez introduire. Une application complexe met souvent en ouvre les diff�rentes solutions pour sa variabilit� et son extension. Selon les cas, la variabilit� est int�gr�e par les templates (g�n�rique), par l'h�ritage (ex. : Widget), par les directives de compilation ou l'�dition statique de liens (ex. : d�pendance de plateforme), ou par le chargement dynamique de biblioth�que (ex. : plugin).
Proposer une nouvelle r�ponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plut�t sur le forum de la rubrique pour �aLes sources pr�sent�es sur cette page sont libres de droits et vous pouvez les utiliser � votre convenance. Par contre, la page de pr�sentation constitue une �uvre intellectuelle prot�g�e par les droits d'auteur. Copyright � 2025 Developpez Developpez LLC. Tous droits r�serv�s Developpez LLC. Aucune reproduction, m�me partielle, ne peut �tre faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'� trois ans de prison et jusqu'� 300 000 � de dommages et int�r�ts.