Question

J'ai trois classes de base différentes:

class BaseA
{
public:
    virtual int foo() = 0;
};

class BaseB
{
public:
    virtual int foo() { return 42; }
};

class BaseC
{
public:
    int foo() { return 42; }
};

Je tire alors de la base comme ceci (remplace X par A, B ou C):

class Child : public BaseX
{
public:
    int foo() { return 42; }
};

Comment la fonction est-elle remplacée dans les trois classes de base différentes? Mes trois hypothèses suivantes sont-elles correctes? Y a-t-il d'autres mises en garde?

  • Avec BaseA, la classe enfant ne compile pas, la fonction virtuelle pure n'est pas définie.
  • Avec BaseB, la fonction de l'enfant est appelée lors de l'appel de foo sur un BaseB * ou un enfant *.
  • Avec BaseC, la fonction dans l'enfant est appelée lors de l'appel de foo sur Child * mais pas sur BaseB * (la fonction de la classe parent est appelée).
Était-ce utile?

La solution

Dans la classe dérivée, une méthode est virtuelle si elle est définie comme virtuelle dans la classe de base, même si le mot clé virtual n'est pas utilisé dans la méthode de la classe dérivée.

  • Avec BaseA , il se compilera et s'exécutera comme prévu, foo () étant virtuel et s'exécutant dans la classe Child .
  • Identique à BaseB , il sera également compilé et exécuté comme prévu, foo () étant virtual () et s'exécutant dans la classe Child . .
  • Avec BaseC , il sera compilé et exécuté, mais exécutera la version BaseC si vous l'appelez à partir du contexte de BaseC . et la version Child si vous appelez avec le contexte Child .

Autres conseils

La règle importante à retenir est qu'une fois qu'une fonction est déclarée virtuelle, les fonctions avec des signatures correspondantes dans les classes dérivées sont toujours virtuelles. Donc, il est écrasé pour Child of A et Child of B, qui se comporteraient de la même manière (à l’exception de vous ne pouvez pas instancier directement BaseA).

Avec C, cependant, la fonction n’est pas remplacée, mais surchargée. Dans cette situation, seul le type statique est important: il l'appellera pour indiquer un pointeur sur (le type statique) au lieu de ce que l'objet est réellement (le type dynamique)

  

Avec BaseA, la classe enfant ne   compile, la fonction virtuelle pure   n'est pas défini

Cela n’est vrai que si vous essayez de créer un objet de BaseA. Si vous créez un objet de Child et que vous pouvez ensuite appeler foo () à l'aide de BaseA * ou de Child *

  

Avec BaseB, la fonction dans l'enfant   est appelé lors de l'appel de foo sur un BaseB *   ou enfant *.

Dépend du type de l'objet car celui-ci peut être BaseB ou Child. Si l'objet est BaseB, BaseB :: foo est appelé.

  

Avec BaseC, la fonction dans l'enfant   est appelé lors de l'appel de foo sur Child *   mais pas sur BaseB * (la fonction dans   la classe parente est appelée).

Oui, mais vous ne voulez jamais faire cela.

Du point de vue du polymorphisme, préférez A, pour que vous sachiez que chaque enfant a sa propre implémentation de la fonction virtuelle.
Choisissez principalement B si vous avez une implémentation par défaut valide, mais vous devez ensuite vous assurer que toutes les classes enfant ont leur propre implémentation si nécessaire. C n’est pas un polymorphisme, utilisez donc judicieusement.

Cela dépend surtout de la façon dont vous l'avez appelé.

si vous l'avez fait:

class Child : public BaseA
{
public:
    int foo() { return 42; }
};

et a fait

BaseA baseA = new Child();
baseA->foo();

Il appellerait la fonction foo de Child.

Cependant, si vous avez fait ceci:

BaseA baseA = new BaseA();

Cela produirait une erreur de compilation.

La classe Child sera compilée si dérivée de A, vous ne pouvez pas instancier des objets de ce type.

Cela pourrait être utile si vous vouliez remplacer certaines fonctions de Base, puis dériver à nouveau.

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