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?

¿Fue útil?

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();
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top