Est-il possible de transmettre covariance déclarer?
-
12-09-2019 - |
Question
Supposons que j'ai ces classes abstraites Foo
et Bar
:
class Foo;
class Bar;
class Foo
{
public:
virtual Bar* bar() = 0;
};
class Bar
{
public:
virtual Foo* foo() = 0;
};
On suppose en outre que je la classe dérivée ConcreteFoo
et ConcreteBar
. Je veux raffiner covariante le type de retour des méthodes de foo()
et bar()
comme ceci:
class ConcreteFoo : public Foo
{
public:
ConcreteBar* bar();
};
class ConcreteBar : public Bar
{
public:
ConcreteFoo* foo();
};
Ce ne compilera pas depuis notre compilateur monopasse bien-aimé ne sait pas que ConcreteBar
va hériter de Bar
, et que ConcreteBar
est un type de retour covariant parfaitement légal. Plaine déclarant avant ConcreteBar
ne fonctionne pas non plus, car il ne dit pas quoi que ce soit du compilateur sur l'héritage.
Est-ce un défaut de C ++ Je vais devoir vivre avec ou est-il réellement un moyen de contourner ce dilemme?
La solution
Vous pouvez simuler assez facilement, mais vous perdez le contrôle de type statique. Si vous remplacez la dynamic_casts
par static_casts
, vous avez ce que le compilateur utilise en interne, mais vous avez pas de vérification de type dynamique ni statique:
class Foo;
class Bar;
class Foo
{
public:
Bar* bar();
protected:
virtual Bar* doBar();
};
class Bar;
{
public:
Foo* foo();
public:
virtual Foo* doFoo();
};
inline Bar* Foo::bar() { return doBar(); }
inline Foo* Bar::foo() { return doFoo(); }
class ConcreteFoo;
class ConcreteBar;
class ConcreteFoo : public Foo
{
public:
ConcreteBar* bar();
protected:
Bar* doBar();
};
class ConcreteBar : public Bar
{
public:
ConcreteFoo* foo();
public:
Foo* doFoo();
};
inline ConcreteBar* ConcreteFoo::bar() { return &dynamic_cast<ConcreteBar&>(*doBar()); }
inline ConcreteFoo* ConcreteBar::foo() { return &dynamic_cast<ConcreteFoo&>(*doFoo()); }
Autres conseils
Ne polymorphisme statique résoudre votre problème? L'alimentation de la classe de base avec la classe dérivée par un argument de modèle? Ainsi, la classe de base va connaître le type dérivé et déclarer? Virtuelle appropriée
Covariance est basé sur l'héritage diagramme, donc, puisque vous ne pouvez pas déclarer
class ConcreteBar : public Bar;
donc aucun moyen de dire compilateur sur la covariance.
Mais vous pouvez le faire avec l'aide de modèles, déclarer ConcretFoo :: barre en tant que modèle et englobante plus tard, vous permet de résoudre ce problème
Qu'en est-ce.
template <class BarType>
class Foo
{
public:
virtual BarType* bar() = 0;
};
template <class FooType>
class Bar
{
public:
virtual FooType* foo() = 0;
};
class ConcreteBar;
class ConcreteFoo : public Foo<ConcreteBar>
{
public:
ConcreteBar* bar();
};
class ConcreteBar : public Bar<ConcreteFoo>
{
public:
ConcreteFoo* foo();
};