【问题标题】:Casting to non base class but with common ancestors转换为非基类但具有共同祖先
【发布时间】:2018-04-12 10:49:13
【问题描述】:

假设我们有以下类:

class A
{
public:
   A() {}

};

class B
{
public:
   B() {}
   virtual ~B() {}
};

template<typename T>
class BB: public B
{
public:
    BB() {}
};

class C: public A, public BB<bool>
{
public:
    C() {}
};

class D: public A, public B
{
public:
    D() {}
};

C 对象转换为类类型D 是否可能/允许/安全?这是为了访问非模板化的东西并使用多态性。

我试过并得到错误no matching function for call to 'D::D(C&amp;)'

添加构造函数D::D(C&amp; c): A(c), B(c) {} 就足够了吗?

请注意,我目前正在使用 C++11,我必须坚持使用它,因此我需要一个兼容的解决方案,但是可能会有更好的解决方案与更高的标准,所以你仍然可以分享这些为了我的知识。

编辑:在阅读了 cmets 之后,这里对我的问题进行了一些进一步的解释

BBB 的定义无法更改,就像 API 中无法修改的类一样。

直接铸造是调用构造函数并创建一个新对象,这不是我想要的,因此它需要答案中提到的间接

鉴于这个其他类:

class Cbis: public A, public BB<float>
{
public:
    Cbis() {}
};

D 类的唯一用途是允许将 CCbis 引用存储在同一个容器中,并且能够访问来自 AB 类的方法。

最后,这可能根本不可能,因为即使有共同的祖先,D 不是基类。

因此,有什么替代方案?除了存储在两个单独的容器中,一个基于A 指针和B 指针。

【问题讨论】:

  • 如果你将它实例化为C,你不能期望它是D类型,因此不是有效的转换。
  • @Neijwiert 我会走得更远。并不是说您不能期望C 的实例也是D 的实例,因为这意味着它可能是一个实例,但您不能确定。 C 的实例不是D 的实例。
  • 如果你的意图是创建新的,而不是使用指针或引用,那么多态与它无关。就您提供的小细节而言,您采用了正确的方法。
  • 我认为这是个好问题 - C 是 A,CBBD 也是 AD 是 @ 987654349@,最后一个BB 是一个B。但这一切仍然不意味着CD!另外,我建议先编译看看编译器是怎么说的。
  • 同样遵循@JeromeReinländer,您可以通过AB 继承C(仅,没有更多类)来大大简化这一点。 A 仍然无法转换为 B,反之亦然。

标签: c++ templates inheritance polymorphism multiple-inheritance


【解决方案1】:

将 C 对象转换为类类型 D 是可能的/允许的/安全的吗?这是为了访问非模板化的东西并使用多态性。

间接是获得运行时多态性所必需的。

如果C 对象被间接引用,那么您可以dynamic_castD 引用(指针)的引用(或指针),因为它们有共同的祖先(具有虚拟职能)。当且仅当该C 对象是也继承D 的派生类的基类时,转换才会成功。如果不是这种情况,dynamic_cast 将安全失败。

添加构造函数D::D(C&amp; c): A(c), B(c) {} 就足够了吗?

添加转换构造函数将使类型(如果构造函数不是explicit 则隐含地)可转换为另一个类型。使用这样的构造函数,可以使用static_cast 显式完成转换。重要的是要了解转换的结果(从CD)不再是C 对象。

【讨论】:

  • 但是在构建程序时需要启用类型信息,以便可以使用dynamic_cast,因为如果要使用C++11,则不一定要启用它。不过答案很好。
  • 对于开箱即用的 C++11,假定类型信息已启用。
  • @user2079303 我编辑了我的问题以澄清我正在寻找的行为,您的回答证实了我的想法,但我仍在寻找最佳选择
【解决方案2】:

是的,可以使用reinterpret_castlink.

安全吗?一点也不! reinterpret_cast 告诉编译器忽略所有内容,简单地将 Obj2 的对象指针视为 C 的对象,它在此示例中起作用,因为字节恰好对齐,只需更改函数的顺序或添加其他函数都会导致它崩溃。

【讨论】:

  • 可能提到它是undefined behaviour
  • 为什么还要提到 reinterpret_cast?我是认真的,这就像给某人一把上膛的枪并说“这不安全,但玩得开心”
  • @StoryTeller 我同意,但这可能有助于 OP 理解这些情况下使用的术语。
  • 提醒一下总是好的,reinterpret_cast 确实看起来太危险了,除非我能保证字节顺序?
  • 是的,字节必须相同;它有它的用途,尽管在普通的 OOP 中它几乎总是一个错误。假设您有一个消息队列并且正在传递结构,前几个字节是标头,然后是正文,然后您始终可以读取标头并将其重新解释为任何结构。类似的东西。
猜你喜欢
  • 2019-03-31
  • 1970-01-01
  • 2015-12-24
  • 2014-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多