web-dev-qa-db-fra.com

Est-ce que TOUTES les fonctions virtuelles doivent être implémentées dans des classes dérivées?

Cela peut sembler une question simple, mais je ne trouve la réponse nulle part ailleurs.

Supposons que j'ai les éléments suivants:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

Est-ce correct que la classe Derived n'implémente pas la fonction bar ()? Et si TOUTES mes classes dérivées n’ont pas besoin de la fonction bar (), mais certaines le font. Toutes les fonctions virtuelles d'une classe de base abstraite doivent-elles être implémentées dans les classes dérivées, ou uniquement celles qui sont virtuelles? Merci

81
mikestaub

Les classes dérivées ne doivent pas implémenter toutes les fonctions virtuelles elles-mêmes. Ils doivent seulement implémenter ceux purs.1 Cela signifie que la classe Derived de la question est correcte. Il hérite l'implémentation bar de sa classe ancêtre, Abstract. (Cela suppose que Abstract::bar est implémenté quelque part. Le code dans la question déclare la méthode, mais ne la définit pas. Vous pouvez le définir en ligne comme la réponse de Trenki s'affiche ou vous pouvez le définir séparément.)


1 Et même alors, seulement si la classe dérivée va être instanciée. Si une classe dérivée n'est pas instanciée directement, mais existe uniquement en tant que classe de base de classes plus dérivées, c'est ceux-là qui sont responsables de la mise en œuvre de toutes leurs méthodes virtuelles pures. La classe "moyenne" de la hiérarchie est autorisée à laisser certaines méthodes virtuelles pures non implémentées, tout comme la classe de base. Si la classe "moyenne" fait implémente une méthode virtuelle pure, ses descendants hériteront de cette implémentation, ils n'auront donc pas à la ré-implémenter eux-mêmes.

72
Rob Kennedy

Seules les méthodes virtuelles pures doivent être implémentées dans des classes dérivées, mais vous avez toujours besoin d'une définition (et pas simplement d'une déclaration) des autres méthodes virtuelles. Si vous n'en fournissez pas, l'éditeur de liens pourrait très bien se plaindre.

Donc, il suffit de mettre {} après que votre méthode virtuelle facultative vous donne une implémentation par défaut vide:

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

Une implémentation par défaut plus complexe irait dans un fichier source séparé.

42
trenki

La norme ISO C++ spécifie que toutes les méthodes virtuelles d'une classe qui ne sont pas virtuelles doivent être définies.

En termes simples, la règle est la suivante:
Si votre classe dérivée dépasse la méthode virtuelle Base class, elle devrait également fournir une définition. Sinon, la classe Base devrait fournir la définition de cette méthode.

Conformément à la règle ci-dessus dans votre exemple de code, virtual void bar(); a besoin d'une définition dans la classe de base.

Référence:

C++ 03 Standard: 10.3 Fonctions virtuelles [class.virtual]

Une fonction virtuelle déclarée dans une classe doit être définie ou déclarée pure (10.4) dans cette classe, ou les deux; mais aucun diagnostic n'est requis (3.2).

Vous devez donc soit rendre la fonction pure virtuelle, soit en fournir une définition.

Le gcc faq le doccoque également:

La norme ISO C++ spécifie que toutes les méthodes virtuelles d'une classe qui ne sont pas virtuelles doivent être définies, mais ne nécessite aucun diagnostic pour les violations de cette règle [class.virtual]/8. Sur la base de cette hypothèse, GCC n'émettra que les constructeurs définis implicitement, l'opérateur d'affectation, le destructeur et la table virtuelle d'une classe de l'unité de traduction qui définit sa première méthode non inline de ce type.

Par conséquent, si vous ne définissez pas cette méthode particulière, l'éditeur de liens peut se plaindre de l'absence de définitions pour les symboles apparemment non liés. Malheureusement, pour améliorer ce message d'erreur, il peut s'avérer nécessaire de modifier l'éditeur de liens, ce qui ne peut pas toujours être fait.

La solution consiste à s'assurer que toutes les méthodes virtuelles qui ne sont pas pures sont définies. Notez qu'un destructeur doit être défini même s'il est déclaré pur-virtuel [class.dtor]/7.

7
Alok Save

Oui, c'est bien ... il vous suffit d'implémenter des fonctions virtuelles pures pour instancier une classe dérivée d'une classe de base abstraite.

3
Jason

Oui, il est correct qu'une classe dérivée doive SUPPRIMER la fonction qui est Pure Virtual dans la classe parente. La classe parent ayant une fonction virtuelle pure est appelée classe abstraite uniquement parce que sa classe enfant doit donner son propre corps de la fonction virtuelle pure.

Pour les fonctions virtuelles normales: - Il n'est pas nécessaire de les redéfinir davantage, car certaines classes enfant peuvent avoir cette fonction, d'autres pas.

Le mécanisme principal de la fonction virtuelle a pour objet le polymorphisme à l'exécution, que l'objectif principal de la fonction virtuelle pure (classe abstraite) soit de rendre obligatoire le fait d'avoir le même nom Function avec le corps de own.

0
CodeCodeCode