17

假设我有这些抽象类FooBar

class Foo;
class Bar;

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

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

进一步假设我有派生类ConcreteFooConcreteBar. 我想协变地改进foo()bar()方法的返回类型,如下所示:

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

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

这不会编译,因为我们心爱的单通道编译器不知道ConcreteBar它将继承自Bar,因此这ConcreteBar是一个完全合法的协变返回类型。简单的前向声明ConcreteBar也不起作用,因为它不会告诉编译器任何有关继承的信息。

这是我必须忍受的 C++ 的一个缺点,还是实际上有办法解决这个困境?

4

4 回答 4

5

你可以很容易地伪造它,但你会失去静态类型检查。如果您替换dynamic_castsby static_casts,则您拥有编译器内部使用的内容,但您没有动态或静态类型检查:

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()); }
于 2009-08-11T09:33:13.313 回答
4

静态多态不能解决你的问题吗?通过模板参数为基类提供派生类?所以基类会知道派生类型并声明一个适当的虚拟?

于 2011-02-14T19:08:42.087 回答
3

这个怎么样。

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();
};
于 2017-08-31T05:08:26.740 回答
2

协方差是基于继承图的,所以既然你不能声明

class ConcreteBar : public Bar;

因此无法告诉编译器协方差。

但是你可以在模板的帮助下做到这一点,将 ConcretFoo::bar 声明为模板,稍后的边界允许你解决这个问题

于 2009-08-11T09:33:32.657 回答