2015-04-08 1 views
1

J'ai deux classes. Classe de base Parent et classe dérivée Child. La classe Parent a une fonction virtuelle pure qui retourne son type de classe. Comment puis-je le remplacer dans une classe dérivée?Fonction de remplacement qui retourne le type de base

class Parent 
{ 
    public: 
     virtual Parent* OverrideMe(Parent* func) = 0; 
}; 

class Child : public Parent 
{ 
    public: 
     Child* OverrideMe(Child* func) override; 
}; 

J'ai essayé Child* OverrideMe(Child* func) override; mais je me retrouve avec l'erreur qu'il ne remplace pas un membre de la classe de base.

+0

Bien que C++ ne le supporte pas, la contravariance nécessiterait un paramètre moins spécifique que 'Parent *', pas plus spécifique. Le fait est que vous pouvez utiliser 'Parent' et ne pas connaître' Child'. Passer un 'Parent * 'qui n'est pas un' Child * 'casserait des choses. – chris

+0

Votre conception est erronée. Il devrait être 'Parent virtuel * OverrideMe (Child * func) = 0; (avec un avant à l'enfant). Pourtant, c'est moche. Vous pouvez faire en sorte que Parent et l'enfant dérivent d'un nœud (en évitant l'héritage de parent à enfant). –

Répondre

3

Si C++ avait pleine covariance et le soutien de contravariance, la relation correcte serait contravariante en entrée et covariant en sortie. A savoir:

struct Organism { }; 

struct Animal : Organism { 
    virtual Animal* OverrideMe(Animal*) = 0; 
}; 

struct Dog : Aniaml { 
    Dog* OverrideMe(Organism*) override { ... } 
    ↑↑↑    ↑↑↑↑↑↑↑↑ 
    covariant  contravariant 
}; 

Cela semble un peu inintéressant, mais cela a du sens. Si vous attendez un Animal*, vous devriez être en mesure de gérer tout ce qui est un Animal* (dont un Dog* se qualifie). Inversement, si vous effectuez une opération sur un Animal*, vous avez juste besoin d'une opération qui peut prendre un Animal* - et une opération qui prend un Organism* se qualifie sur ce front.

Notez que si l'entrée était co variante, cela casserait le système de type. Considérez quelque chose comme:

Animal* a = new Dog; 
a->OverrideMe(new Cat); 

Si Dog::OverrideMe ont été autorisés à prendre un Dog*, ce serait l'échec - un Cat* n'est pas un Dog*! Il est donc permis de prendre un Animal* ... ou quelque chose de plus générique que cela (par exemple Organism*), puisque tout cela fonctionne bien.

C++ ne pas un support pour contravariance en entrée, seulement covariance en sortie. Donc, vous pouvez écrire soit:

Dog* OverrideMe(Animal*) override { ... } 

ou:

Animal* OverrideMe(Animal*) override { .... } 

mais rien d'autre.

3

Le type du paramètre de fonction et les qualificatifs cv de la fonction doivent être les mêmes. Vous pouvez donc utiliser

Child* OverrideMe(Parent* func) override; 
2

Vous ne surchargez pas ici parce que votre fonction OverrideMe ne prend pas les mêmes arguments que la fonction dans la classe de base que vous essayez de passer outre:

class Parent 
{ 
    public: 
     virtual Parent* OverrideMe(Parent* func) = 0; 
}; 

class Child : public Parent 
{ 
    public: 
     virtual Child* OverrideMe(Parent* func) override; 
}; 
0

Cette "ça sent mauvais", en d'autres termes, vous "brisez" la normale "tout objet devrait être remplaçable avec tout autre objet qui en dérive".

Si vous avez une fonction d'interface dans la classe de base, la fonction doit prendre le même type dans la hiérarchie de classe.

Donc, la bonne chose est à:

Parent * OverrideMe (Parent * func) override; (Vous pouvez, comme le dit juanchopanza, renvoyer un type dérivé, mais êtes-vous sûr que la valeur retournée par le père sera TOUJOURS la même classe? Pour moi, cela ressemble au type de fonction qui pourrait renvoyer "tout dérivé objet ", auquel cas vous seriez soit allongé ou finissez avec" effets intéressants ")

Si pour une raison quelconque cela ne fonctionne pas réellement dans votre cas, alors vous ne devriez probablement pas utiliser l'héritage de cette façon.