Is there a way to forward declare covariance?

浪尽此生 提交于 2019-12-05 11:37:50

问题


Suppose I have these abstract classes Foo and Bar:

class Foo;
class Bar;

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

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

Suppose further that I have the derived class ConcreteFoo and ConcreteBar. I want to covariantly refine the return type of the foo() and bar() methods like this:

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

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

This won't compile since our beloved single pass compiler does not know that ConcreteBar will inherit from Bar, and so that ConcreteBar is a perfectly legal covariant return type. Plain forward declaring ConcreteBar does not work, either, since it does not tell the compiler anything about inheritance.

Is this a shortcoming of C++ I'll have to live with or is there actually a way around this dilemma?


回答1:


You can fake it quite easily, but you lose the static type checking. If you replace the dynamic_casts by static_casts, you have what the compiler is using internally, but you have no dynamic nor static type check:

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



回答2:


Doesn't static polymorphism solve your problem? Feeding the base class with the derived class through template argument? So the base class will know the derivative Type and declare a proper virtual?




回答3:


Covariance is based on inheritance diagram, so since you cannot declare

class ConcreteBar : public Bar;

hence no way to tell compiler about covariance.

But you can do it with help of templates, declare ConcretFoo::bar as template and later bounding allows you solve this problem




回答4:


How about this.

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


来源:https://stackoverflow.com/questions/1259272/is-there-a-way-to-forward-declare-covariance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!