Pergunta

Suponha que eu tenho essas classes abstratas Foo e Bar:

class Foo;
class Bar;

class Foo
{
public:
  virtual Bar* bar() = 0;
};

class Bar
{
public:
  virtual Foo* foo() = 0;
};

Suponha ainda que eu tenho a ConcreteFoo classe derivada e ConcreteBar. Quero aperfeiçoar covariantemente o tipo de retorno dos métodos foo() e bar() assim:

class ConcreteFoo : public Foo
{
public:
  ConcreteBar* bar();
};

class ConcreteBar : public Bar
{
public:
  ConcreteFoo* foo();
};

Isso não irá compilar uma vez o nosso amado compilador única passagem não sabe que ConcreteBar vai herdar de Bar, e assim que ConcreteBar é um tipo covariant retorno perfeitamente legal. Plain frente declarando ConcreteBar não funcionar, também, uma vez que não dizer ao compilador nada sobre herança.

Isso é uma lacuna do C ++ eu vou ter que viver com ou há realmente uma maneira de contornar este dilema?

Foi útil?

Solução

Você pode fingir isso muito facilmente, mas você perde a verificação de tipo estático. Se você substituir o dynamic_casts por static_casts, você tem o que o compilador está usando internamente, mas você não tem dinâmica nem verificação de tipo estático:

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()); }

Outras dicas

não polimorfismo estático resolveu seu problema? Alimentando a classe base com a classe derivada através de argumento modelo? Assim, a classe base vai saber o tipo de derivativo e declarar uma adequada virtual?

Covariance é baseado no diagrama de herança, por isso, desde que você não pode declarar

class ConcreteBar : public Bar;

, portanto, nenhuma maneira de dizer compilador sobre covariância.

Mas você pode fazê-lo com a ajuda de modelos, declarar ConcretFoo :: bar como modelo e depois saltando permite resolver este problema

Como sobre isso.

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top