假设我有这些抽象类Foo
和Bar
:
class Foo;
class Bar;
class Foo
{
public:
virtual Bar* bar() = 0;
};
class Bar
{
public:
virtual Foo* foo() = 0;
};
进一步假设我有派生类ConcreteFoo
和ConcreteBar
。我想协变地优化foo()
和bar()
方法的返回类型,如下所示:
class ConcreteFoo : public Foo
{
public:
ConcreteBar* bar();
};
class ConcreteBar : public Bar
{
public:
ConcreteFoo* foo();
};
这不会编译,因为我们心爱的单通道编译器不知道ConcreteBar
将继承Bar
,因此ConcreteBar
是完全合法的协变返回类型。简单地向前声明ConcreteBar
也不起作用,因为它没有告诉编译器有关继承的任何信息。
这是否是我不得不忍受的C ++的缺点,还是实际上有办法解决这个难题?
答案 0 :(得分:4)
你可以很容易地伪造它,但是你失去了静态类型检查。如果您将dynamic_casts
替换为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()); }
答案 1 :(得分:3)
静态多态性不能解决您的问题吗? 通过模板参数为派生类提供基类? 那么基类将知道派生类型并声明一个适当的虚拟?
答案 2 :(得分:2)
协方差基于继承图,因此无法声明
class ConcreteBar : public Bar;
因此无法告诉编译器协方差。
但你可以在模板的帮助下做到这一点,将ConcretFoo :: bar声明为模板,之后绑定可以解决这个问题
答案 3 :(得分:1)
这个怎么样。
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();
};