Avec la définition de structure donnée ci-dessous ...
struct A {
virtual void hello() = 0;
};
Approche n ° 1:
struct B : public A {
virtual void hello() { ... }
};
Approche n ° 2:
struct B : public A {
void hello() { ... }
};
Y a-t-il une différence entre ces deux façons de remplacer la fonction hello?
c++
overriding
virtual-functions
Anarki
la source
la source
Réponses:
Ce sont exactement les mêmes. Il n'y a pas de différence entre eux, sauf que la première approche nécessite plus de frappe et est potentiellement plus claire.
la source
override
mot - clé.La «virtualité» d'une fonction se propage implicitement, cependant au moins un compilateur que j'utilise générera un avertissement si le
virtual
mot-clé n'est pas utilisé explicitement, donc vous voudrez peut-être l'utiliser si ce n'est que pour garder le compilateur silencieux.D'un point de vue purement stylistique, le
virtual
mot - clé «annonce» clairement le fait à l'utilisateur que la fonction est virtuelle. Cela sera important pour toute personne de la sous-classe B sans avoir à vérifier la définition de A. Pour les hiérarchies de classes profondes, cela devient particulièrement important.la source
Le
virtual
mot-clé n'est pas nécessaire dans la classe dérivée. Voici la documentation à l'appui, tirée du projet de norme C ++ (N3337) (c'est moi qui souligne):la source
Non, le
virtual
mot clé sur les remplacements de fonctions virtuelles des classes dérivées n'est pas requis. Mais il convient de mentionner un écueil connexe: un échec à remplacer une fonction virtuelle.L' échec de substitution se produit si vous avez l'intention de remplacer une fonction virtuelle dans une classe dérivée, mais faites une erreur dans la signature afin qu'elle déclare une fonction virtuelle nouvelle et différente. Cette fonction peut être une surcharge de la fonction de classe de base ou son nom peut différer. Que vous utilisiez ou non le
virtual
mot - clé dans la déclaration de fonction de classe dérivée, le compilateur ne pourra pas dire que vous avez l'intention de remplacer une fonction d'une classe de base.Cet écueil est cependant heureusement résolu par la fonctionnalité de langage de substitution explicite C ++ 11 , qui permet au code source de spécifier clairement qu'une fonction membre est destinée à remplacer une fonction de classe de base:
Le compilateur émettra une erreur de compilation et l'erreur de programmation sera immédiatement évidente (peut-être que la fonction dans Derived aurait dû prendre un
float
comme argument).Reportez-vous à WP: C ++ 11 .
la source
L'ajout du mot clé "virtuel" est une bonne pratique car il améliore la lisibilité, mais ce n'est pas nécessaire. Les fonctions déclarées virtuelles dans la classe de base et ayant la même signature dans les classes dérivées sont considérées comme "virtuelles" par défaut.
la source
Il n'y a aucune différence pour le compilateur lorsque vous écrivez le
virtual
dans la classe dérivée ou l'omettez.Mais vous devez regarder la classe de base pour obtenir ces informations. Par conséquent, je recommanderais d'ajouter le
virtual
mot - clé également dans la classe dérivée, si vous voulez montrer à l'humain que cette fonction est virtuelle.la source
Il y a une différence considérable lorsque vous avez des modèles et commencez à prendre des classes de base comme paramètres de modèle:
La partie amusante est que vous pouvez maintenant définir des fonctions d'interface et non-interface plus tard pour définir des classes. Cela est utile pour l'interfonctionnement des interfaces entre les bibliothèques (ne comptez pas sur cela comme un processus de conception standard d'une seule bibliothèque). Cela ne vous coûte rien de permettre cela pour toutes vos classes - vous pouvez même
typedef
B à quelque chose si vous le souhaitez.Notez que, si vous faites cela, vous voudrez peut-être aussi déclarer des constructeurs copier / déplacer en tant que modèles: autoriser la construction à partir d'interfaces différentes vous permet de «convertir» entre différents
B<>
types.On peut se demander si vous devez ajouter le support pour
const A&
int_hello()
. La raison habituelle de cette réécriture est de passer d'une spécialisation basée sur l'héritage à une spécialisation basée sur un modèle, principalement pour des raisons de performances. Si vous continuez à prendre en charge l'ancienne interface, vous pouvez difficilement détecter (ou dissuader) l'utilisation ancienne.la source
Le
virtual
mot clé doit être ajouté aux fonctions d'une classe de base pour les rendre remplaçables. Dans votre exemple,struct A
est la classe de base.virtual
ne signifie rien pour utiliser ces fonctions dans une classe dérivée. Cependant, si vous voulez que votre classe dérivée soit également une classe de base elle-même et que vous voulez que cette fonction soit remplaçable, vous devrez alors la mettrevirtual
là.Ici
C
hérite deB
,B
n'est donc pas la classe de base (c'est aussi une classe dérivée), etC
est la classe dérivée. Le diagramme d'héritage ressemble à ceci:Vous devez donc mettre les
virtual
fonctions devant les classes de base potentielles qui peuvent avoir des enfants.virtual
permet à vos enfants de remplacer vos fonctions. Il n'y a rien de mal à mettrevirtual
en avant les fonctions à l'intérieur des classes dérivées, mais ce n'est pas obligatoire. Il est cependant recommandé, car si quelqu'un souhaite hériter de votre classe dérivée, il ne serait pas satisfait que la méthode de substitution ne fonctionne pas comme prévu.Mettez donc
virtual
en avant les fonctions dans toutes les classes impliquées dans l'héritage, à moins que vous ne soyez certain que la classe n'aura pas d'enfants qui auraient besoin de remplacer les fonctions de la classe de base. C'est une bonne pratique.la source
Je vais certainement inclure le mot-clé Virtual pour la classe enfant, car
la source