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

91

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

Supposons que j'ai ce qui suit:

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

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

Est-ce normal que la classe Derived n'implémente pas la fonction bar ()? Et si TOUTES mes classes dérivées ont 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 juste celles qui sont purement virtuelles? Merci

Mikestaub
la source

Réponses:

82

Les classes dérivées n'ont pas à implémenter toutes les fonctions virtuelles elles-mêmes. Ils ont seulement besoin de mettre en œuvre les purs . 1 Cela signifie que la Derivedclasse dans la question est correcte. Il hérite de la barmise en œuvre de sa classe ancêtre, Abstract. (Cela suppose qu'elle Abstract::barest implémentée quelque part. Le code de la question déclare la méthode, mais ne la définit pas. Vous pouvez la définir en ligne comme le montre la réponse de Trenki , ou vous pouvez la 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 n'existe qu'en tant que classe de base de classes plus dérivées, alors ce sont ces classes qui sont responsables de l'implémentation de toutes leurs méthodes virtuelles pures. La classe "moyenne" dans 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 » ne mettre en œuvre une méthode virtuelle pure, puis ses descendants hériteront que la mise en œuvre, de sorte qu'ils ne sont pas à nouveau mettre en œuvre eux - mêmes.

Rob Kennedy
la source
3
Et même cela (implémentation de fonctions virtuelles pures) uniquement si elles sont destinées à être instanciées (contrairement au fait d'être une classe de base abstraite elle-même).
Christian Rau
1
C'est ce que je pensais. Mais je fais cela dans mon projet, et j'obtiens une erreur de liaison indiquant qu'il existe un "symbole externe non résolu" pour Derived :: bar (); Mais je n'ai jamais déclaré bar dans Derived, alors pourquoi l'éditeur de liens recherche-t-il le corps de la fonction?
mikestaub
1
@pixelpusher a bien sûr Derived::barun corps de fonction, celui de Abstract::bar. Il semble donc que l'unité de traduction où cela est défini (est-elle même définie quelque part?) N'est pas liée à l'unité de traduction où elle est appelée.
Christian Rau
2
@Rob: They only need to implement the pure ones.C'est trompeur. Les classes dérivées n'ont pas nécessairement besoin d'implémenter des fonctions virtuelles pures non plus.
Nawaz
J'apprécie l'aide mais @trenki a frappé dans le mille. Bien que vous ayez également raison Christian Rau, car il n'a pas été défini.
mikestaub
47

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 seulement d'une déclaration) des autres méthodes virtuelles. Si vous n'en fournissez pas un, l'éditeur de liens pourrait très bien se plaindre.

Donc, mettre juste {}après 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 impliquée irait cependant dans un fichier source séparé.

Trenki
la source
7

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

En termes simples, la règle est la suivante:
si votre classe dérivée remplace la méthode virtuelle de la classe de base, elle doit également fournir une définition.Sinon, la classe de base doit fournir la définition de cette méthode.

Conformément à la règle ci-dessus dans votre exemple de code, virtual void bar();nécessite 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 purement virtuelle, soit lui fournir une définition.

La faq gcc le révèle également:

La norme ISO C ++ spécifie que toutes les méthodes virtuelles d'une classe qui ne sont pas purement 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 dans l'unité de traduction qui définit sa première méthode non en ligne.

Par conséquent, si vous ne parvenez pas à définir cette méthode particulière, l'éditeur de liens peut se plaindre du manque de définitions pour des symboles apparemment sans rapport. Malheureusement, pour améliorer ce message d'erreur, il peut être nécessaire de modifier l'éditeur de liens, ce qui ne peut pas toujours être fait.

La solution est de 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.

Alok Save
la source
3

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

Jason
la source
1

Oui, il est correct qu'une classe dérivée doit SUPPRIMER la fonction qui est Pure Virtual dans la classe parent. 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 remplacer davantage, car certaines classes enfants peuvent avoir cette fonction, d'autres ne l'ont pas.

L'objectif principal du mécanisme de fonction virtuelle est le polymorphisme d'exécution, si l'objectif principal de la fonction virtuelle pure (classe abstraite) est de rendre obligatoire le même nom Function avec son propre corps.

CodeCodeCode
la source