¿Hay una manera de desviar la covarianza declarar?
-
12-09-2019 - |
Pregunta
Supongamos que tengo estas clases abstractas y Foo
Bar
:
class Foo;
class Bar;
class Foo
{
public:
virtual Bar* bar() = 0;
};
class Bar
{
public:
virtual Foo* foo() = 0;
};
Supongamos, además, que he la ConcreteFoo
clase y ConcreteBar
derivada. Quiero afinar covariantly el tipo de retorno de los métodos foo()
y bar()
como esta:
class ConcreteFoo : public Foo
{
public:
ConcreteBar* bar();
};
class ConcreteBar : public Bar
{
public:
ConcreteFoo* foo();
};
Esto no va a compilar ya nuestro querido compilador de una sola pasada no sabe que ConcreteBar
heredará del Bar
, y para que ConcreteBar
es un tipo de retorno covariantes perfectamente legal. Llanura hacia adelante declarando ConcreteBar
no funciona, tampoco, ya que no le dice al compilador nada de la herencia.
¿Es esto un defecto de C ++ que voy a tener que vivir con o hay en realidad una forma de evitar este dilema?
Solución
Se puede fingir con bastante facilidad, pero se pierde la comprobación de tipo estático. Si reemplaza el dynamic_casts
por static_casts
, tiene lo que el compilador está utilizando internamente, pero no tiene cheque tipo dinámico ni estática:
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()); }
Otros consejos
No polimorfismo estática a resolver su problema? La alimentación de la clase base con la clase derivada a través de argumento de plantilla? Por lo que la clase base se conoce el tipo de derivado y declarar un virtual adecuado?
covarianza se basa en diagrama de herencia, por lo que ya no se puede declarar
class ConcreteBar : public Bar;
lo tanto no hay manera de saber compilador acerca de covarianza.
Sin embargo, puede hacerlo con ayuda de plantillas, declarar ConcretFoo :: bar como plantilla y después de delimitación permite a solucionar este problema
¿Qué hay de esto.
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();
};