8
votes

Membres de la classe de base virtuels

Pourquoi il est recommandé de ne pas avoir de membres de données dans la classe de base virtuelle?

Qu'en est-il des membres de la fonction? Si j'ai une tâche commune à toutes les classes dérivées, c'est bien pour que la classe de base virtuelle effectue la tâche ou si le hérité dérivé de deux classés - d'une interface virtuelle et d'une base simple qui effectue la tâche?

Merci.


1 commentaires

Pourriez-vous fournir un lien ou une citation pour les conseils? Je ne vois pas beaucoup de point pour marquer une classe de base virtuelle s'il n'a pas de membres de données, car l'objectif le plus courant de l'héritage virtuel est d'empêcher la duplication des membres de la classe de base. Par exemple, dans les bibliothèques standard, iOS_BASE dispose de membres de données et est une classe de base virtuelle (via iOS) de Istream et d'Otstream. Donc, j'avais presque (mais pas tout à fait) dire l'inverse - si vous allez avoir une classe de base virtuelle, il devrait avoir des membres de données, sinon hériter non-pratiquement.


5 Réponses :


0
votes

a) Les membres doivent être privés - vous pouvez donc avoir des problèmes les utiliser dans des classes dérivées (vous devez donc ajouter des méthodes de getter et de réglage, qui explosent votre interface)

B) Ne déclarez pas les choses que vous n'utilisez pas actuellement - déclarez des variables uniquement dans des classes qui les accédent / utilisez-les

c) Les classes de base virtuelles ne doivent contenir que les interfaces / méthodes virtuelles, rien de plus

J'espère que cela contribue un peu, même si mes raisons ne sont pas parfaites et complètes :)

ciao, Chris


0 commentaires

11
votes

En pratique, vous ne devez utiliser que l'héritage virtuel pour définir des interfaces car ils sont généralement utilisés avec de multiples héritage pour garantir qu'une seule version de la classe est présente dans la classe dérivée. Et les interfaces pures sont la forme la plus sûre de multiples héritage. Bien sûr, si vous savez ce que vous faites, vous pouvez utiliser plusieurs héritiers comme vous le souhaitez, mais cela peut entraîner un code fragile si vous ne faites pas attention.

Le plus grand inconvénient avec héritage virtuel est si leurs constructeurs prennent des paramètres. Si vous devez passer des paramètres sur le constructeur d'une classe de base virtuelle, vous forcez toutes les classes dérivées pour appeler explicitement le constructeur (ils ne peuvent pas compter sur une classe de base appelant le constructeur).

La seule raison pour laquelle je peux voir Pour votre conseils explicite, c'est que les données de votre classe de base virtuelle, celles-ci pourraient nécessiter des paramètres de constructeur.

EDIT J'ai fait du travail à la maison après le commentaire de Martin, merci Marin. La première ligne n'est pas tout à fait vraie:

comme une pratique que vous devriez utiliser seulement héritage virtuel à définir interfaces comme ils sont généralement utilisés avec multiple héritage pour assurer que seule une version de la classe est présent dans la classe dérivée.

Héritage virtuel ne fait aucune différence si la classe de base est une interface pure (à l'exception des erreurs de compilateur légèrement différentes, en VC8, si toutes les méthodes ne sont pas implémentées). Il ne fait qu'une vraie différence si la classe de base comporte des données, dans ce cas, vous vous retrouvez avec un diamant plutôt qu'une forme en U xxx

dans le cas virtuel b et c La même copie de A.

Cependant, je suis toujours d'accord avec tout le reste des interfaces pures étant la forme la plus sûre de multiples héritage, même si elles ne nécessitent pas de héritage virtuel. Et le fait que les paramètres du constructeur et l'héritage virtuel sont une douleur.


2 commentaires

+1 Ceci est également résumé sur le C ++ FAQ Lite New-brunswick.net/workshop/c ++ / FAQ / ...


Je ne pense pas que cela ne soit vrai.



1
votes

Je n'ai jamais vu cette recommandation.

Une classe est un ensemble de fonctions et de données étroitement liées. L'objectif d'une classe de base est d'avoir un ensemble commun de fonctions et de données disponibles pour la réutilisation par des classes dérivées.

Je pense que vous ne vous limiterez pas à ne pas avoir de membres de données ni de fonctions virtuelles non pure dans les classes de base réduira la quantité de réutilisation de code, ce qui conduit à un code moins fiable à long terme.


2 commentaires

Si vous pouvez obtenir une copie de "efficace C ++", lisez l'élément 20: "Évitez les membres de données dans des interfaces publiques".


Droite, je suis d'accord avec ça. Je ne suggère pas que les membres de données soient publics. En tout cas, j'ai mal compris la question et pensez que la réponse de IAIN est bonne.



2
votes

Le conseil de base est d'avoir un constructeur par défaut dans la base virtuelle. Si vous ne le faites pas, alors tous les la classe la plus dérivée em> (c'est-à-dire une sous-classe) doit appeler la base virtuelle CTOR explicitement, et qui conduit à des collègues en colère frapper sur votre porte de bureau ...

class VirtualBase {
public:
    explicit VirtualBase( int i ) : m_i( i ) {}
    virtual ~VirtualBase() {}

private:
    int m_i;
};

class Derived : public virtual VirtualBase {
public:
    Derived() : VirtualBase( 0 ) {} // ok, this is to be expected
};

class DerivedDerived : public Derived { // no VirtualBase visible
public:
    DerivedDerived() : Derived() {} // ok? no: error: need to explicitly
                                    // call VirtualBase::VirtualBase!!
    DerivedDerived() : VirtualBase( 0 ), Derived() {} // ok
};


2 commentaires

Vous voulez dire si je n'avais pas appelé explicitement Ctor de base virtuelle, il ne sera pas appelé lorsque je crée l'objet dérivé?


Vous avez d'appeler la classe de base virtuelle CORT dans Chaque la mise en œuvre de la CTOR dérivée, le compilateur ne vous laissera pas vous échapper autrement. La seule exception: si la base virtuelle a une CTOR par défaut, celle-ci appelle lorsque vous n'en appelez pas explicitement un autre.



0
votes

Les classes de base All-Abtract utilisées pour simuler des interfaces dans C ++ ne doivent pas avoir des membres de données - car ils décrivent une interface et l'état d'instance est un détail de mise en œuvre.

Autre que cela, les classes de base contenant des fonctions virtuelles peuvent bien avoir des éléments de données. Les règles habituelles s'appliquent, cependant:

  • Faites-les aussi caché que possible et utilisez des getters and Setters si vous avez besoin de préserver les invariants de classe.
    (Il y a une échappatoire ici: S'il n'y a pas d'invariant associé au député, c'est-à-dire que cela peut assumer une valeur possible à un moment donné, vous pourriez le rendre public. Cependant, cela refuse une classe dérivée en ajoutant un invariant.
  • Conception pour l'héritage: le contrat de votre classe devrait définir les responsabilités et les possibilités d'une classe dérivée, ce qu'elle a besoin / peut écraser à quel but.

0 commentaires