C ++: Comment puis-je éviter « type de retour covariant invalide » dans les classes héritées sans jeter?

StackOverflow https://stackoverflow.com/questions/2410532

  •  18-09-2019
  •  | 
  •  

Question

J'ai une hiérarchie de classes assez complexe dans lequel les classes sont en forme de croix selon les uns des autres: Il existe deux classes abstraites A et C contenant une méthode qui renvoie une instance de C et A, respectivement. Dans leurs classes héritées je veux utiliser un type co-variante, qui est dans ce cas un problème puisque je ne sais pas un moyen de transmettre-déclarer le navire relation d'héritage.

J'obtenir un "test.cpp: 22: Erreur: type non valide de retour covariant pour 'D * B virtuel :: outc ()'" - erreur, car le compilateur ne sait pas que D est une sous-classe de C

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

Si je change le type de retour de B :: outc () à C * l'exemple compile. Est-il possible de garder B * et D * comme types de retour dans les classes héritées (il me serait intuitive qu'il ya une façon)?

Était-ce utile?

La solution

Je ne connais aucun moyen d'avoir des membres covariants couplé directement en C ++. Vous aurez soit d'ajouter une couche, ou mettre en œuvre Covariant vous retourner.

Pour la première option

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class BI : public A {
public:
};

class D : public C {
public:
        BI* outA();
};

class B: public BI {
public:
        D* outC();
};

D* B::outC() {
        return new D();
}

BI* D::outA() {
        return new B();
}

et pour le second

class C;

class A {
public:
        C* outC() { return do_outC(); }
        virtual C* do_outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
        virtual C* do_outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return static_cast<D*>(do_outC());
}

C* B::do_outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

Notez que cette deuxième option est ce qui se fait implicitement par le compilateur (avec des contrôles statiques que le static_cast est valide).

Autres conseils

Pour autant que je sache, il n'y a aucun moyen de le faire sans coulée explicite. Le problème est que la définition de B de classe ne peut pas savoir que D est une sous-classe de C jusqu'à ce qu'il voit une définition complète de D de classe, mais la définition de D de classe ne peut pas savoir que B est une sous-classe de A jusqu'à ce qu'il voit une définition complète de B de classe, et si vous avez une dépendance circulaire. Cela ne peut pas être résolu avec l'avant-déclarations parce qu'une déclaration anticipée ne peut malheureusement pas spécifier une relation d'héritage.

Il y a un problème similaire à essayer de mettre en œuvre une méthode de clone() covariant en utilisant des modèles, que j'ai trouvé peut être résolu , mais la solution analogue ne fonctionne toujours pas ici parce que la référence circulaire reste impossible à résoudre.

Vous ne pouvez pas le faire en raison de l'attente côté client. Lorsque vous utilisez une instance C, vous ne pouvez pas dire quel type de C il est (un D ou autre chose). Ainsi, si vous stockez le pointeur B (résultant d'un appel à la classe dérivée, mais vous ne savez pas au moment de la compilation) en un pointeur, je ne suis pas sûr que tous les trucs de mémoire sera droite.

Lorsque vous appelez une méthode sur un type polymorphes, l'environnement d'exécution doit vérifier le type dynamique de l'objet et il déplace les pointeurs en fonction de la hiérarchie de classe. Je ne suis pas sûr que vous devez compter sur covariance. Jetez un oeil à ce

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