有没有办法转发声明协方差?

发布于 2024-08-01 16:49:11 字数 725 浏览 9 评论 0原文

假设我有这些抽象类 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++ 的缺点吗?或者实际上有办法解决这个困境吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

无远思近则忧 2024-08-08 16:49:11

协方差基于继承图,因此由于您无法声明,

class ConcreteBar : public Bar;

因此无法告诉编译器有关协方差的信息。

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

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

暗喜 2024-08-08 16:49:11

这个怎么样。

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

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();
};
酷到爆炸 2024-08-08 16:49:11

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

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?

魂牵梦绕锁你心扉 2024-08-08 16:49:11

你可以很容易地伪造它,但你会失去静态类型检查。 如果将 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()); }

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()); }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文