Existe uma maneira de transmitir a declarar covariância?
-
12-09-2019 - |
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?
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();
};