Question

http://fr.wikipedia.org/wiki/Diamond_problem

Je sais ce que cela signifie, mais quelles mesures puis-je prendre pour l'éviter?

Était-ce utile?

La solution

Un exemple pratique:

class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};

Notez comment la classe D hérite de B & amp; C. Mais les deux B & amp; C hériter de A. Cela entraînera l'inclusion de 2 copies de la classe A dans la table virtuelle.

Pour résoudre ce problème, nous avons besoin d'un héritage virtuel. C'est la classe A qui doit être virtuellement héritée. Donc, cela résoudra le problème:

class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};

Autres conseils

héritage virtuel. C’est pour ça que ça existe.

Je me contenterais d'utiliser plusieurs héritages d'interfaces. Si l'héritage multiple de classes est parfois attrayant, il peut également être déroutant et douloureux si vous vous en servez régulièrement.

L'héritage est une arme puissante. Utilisez-le uniquement lorsque vous en avez vraiment besoin. Dans le passé, l'héritage en diamants était un signe que j'allais trop loin avec la classification, disant qu'un utilisateur est un "employé". mais ils sont aussi un "auditeur de widget", mais aussi un ...

Dans ces cas, il est facile de résoudre plusieurs problèmes d'héritage.

Je les ai résolus en utilisant la composition et les pointeurs vers le propriétaire:

Avant:

class Employee : public WidgetListener, public LectureAttendee
{
public:
     Employee(int x, int y)
         WidgetListener(x), LectureAttendee(y)
     {}
};

Après:

class Employee
{
public:
     Employee(int x, int y)
         : listener(this, x), attendee(this, y)
     {}

     WidgetListener listener;
     LectureAttendee attendee;
};

Oui, les droits d’accès sont différents, mais si vous pouvez vous en tirer, sans dupliquer le code, c’est mieux, car elle est moins puissante. (Vous pouvez économiser de l'énergie lorsque vous n'avez pas d'autre choix.)

class A {}; 
class B : public A {}; 
class C : public A {}; 
class D : public B, public C {};

En cela, les attributs de la classe A répétés deux fois dans la classe D, ce qui augmente l'utilisation de la mémoire ... Donc, pour économiser de la mémoire, nous créons un attribut virtuel pour tous les attributs hérités de la classe A qui sont stockés dans une table virtuelle.

Le point fort du diamant redouté est qu’il s’agit d’une erreur. Le meilleur moyen d'éviter consiste à déterminer à l'avance la structure de votre héritage. Par exemple, un projet sur lequel je travaille a des visualiseurs et des éditeurs. Les éditeurs sont des sous-classes logiques de visionneuses, mais comme tous les visionneuses sont des sous-classes - TextViewer, ImageViewer, etc., l’éditeur ne dérive pas de Viewer, ce qui permet aux classes TextEditor, ImageEditor finales d’éviter le losange.

Dans les cas où le losange n'est pas évitable, utilisez l'héritage virtuel. Toutefois, avec les bases virtuelles, le plus gros inconvénient est que le constructeur de la base virtuelle doit être appelé par la classe la plus dérivée, ce qui signifie qu’une classe qui en dérive n’a pratiquement aucun contrôle sur les paramètres du constructeur. De plus, la présence d’une base virtuelle a tendance à entraîner une pénalité de performance / d’espace lorsqu’elle passe à travers la chaîne, bien que je ne pense pas qu’il y ait une pénalité plus lourde au-delà de la première.

De plus, vous pouvez toujours utiliser le losange si vous êtes explicite sur la base que vous souhaitez utiliser. Parfois, c'est le seul moyen.

Je suggérerais un meilleur design de classe. Je suis certain que certains problèmes sont mieux résolus grâce à l'héritage multiple, mais vérifiez s'il existe un autre moyen.

Sinon, utilisez les fonctions / interfaces virtuelles.

Utiliser l'héritage par délégation. Ensuite, les deux classes pointeront vers une base A, mais devront mettre en œuvre des méthodes qui redirigent vers A. Cela a pour effet de transformer les membres protégés de A en "privés". membres en B, C et D, mais vous n’avez plus besoin de virtuel ni de diamant.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top