c++中具有多重继承的强制转换

Casting with multiple inheritance in C++

本文关键字:转换 多重继承 c++      更新时间:2023-10-16

下面的代码不能编译,gcc -std=c++11说这是一个无效的静态强制转换:

class A { public: virtual ~A() {} };
class B { public: virtual ~B() {} };
class AD : public A { public: virtual ~AD() {} };
class AB : public B, public A {};
class ADB : public B, public AD {};
int main() {
    ADB adb;
    ADB* ptr = &adb;
    AB* cast = static_cast<AB*>(ptr);
    return 0;
}

我想将类型为ADB的类强制转换为AB。这个感觉应该是安全的——毕竟,ADB的内存结构是B后面跟着AD,而CC_6本身就是A后面跟着AD自己的成员。因此,强制编译器将指针ptr解释为AB似乎总是定义为:

class A { public: virtual ~A() {} };
class B { public: virtual ~B() {} };
class AD : public A { public: virtual ~AD() {} };
class AB : public B, public A {};
class ADB : public B, public AD {};
int main() {
    ADB adb;
    ADB* ptr = &adb;
    AB* cast = reinterpret_cast<AB*>(ptr);
    return 0;
}

这也不会编译,导致链接器抱怨未定义的引用

所以很明显,在某种程度上,虚函数表指针在强制转换时没有"同步",在这种情况下,我需要将ADBAD的单个基类强制转换为ABA。我不是很确定,只是猜测。我该怎么做呢?

只能在对象继承结构中的类之间成功强制转换。因此,您可以将ADB转换为A、B或AD。你对类似内存布局的合理化并不适用。虽然对底层实现的理解可以对某些"如何"answers"为什么"提供有用的见解(特别是当涉及到性能时),但您不应该必须考虑底层实现来理解(或合理化)语言特性的规则。它的工作方式是帮助你表达更高层次的意图。

更重要的是,您永远不应该基于底层实现的知识来规避语言内置的限制。虽然偶尔可以这样做,但大多数情况下,它将导致不可移植的代码或无法在编译器更新后存活的代码-无法编译或在生产中神秘地中断。

无论如何,你关于内存布局的假设可能是不正确的;定义虚析构函数会迫使编译器将虚函数表指针注入到A、B和AD的内存布局中,因此ADB的实际内存布局可能不是您想象的那样。

如果要强制转换AB,则静态强制转换只能将AB强制转换为BA。就是这样。

这是在编译时提供static_cast的保证:它只允许在相关类型之间逻辑 ok的强制转换操作。

您也可以想象这些static_cast,它们将是正确的:

  • 和AD
  • 中的A
  • AB中的B或a
  • ADB中的B或AD
  • 和ADB
  • 中的A

但是在AB和ADB之间的继承层次结构中没有路径来做你想做的事情。AB和ADB绝对不是相关的类型。