静态强制转换 - 无法通过虚拟继承进行强制转换

Static cast - Cannot cast through virtual inheritance

本文关键字:转换 虚拟 继承 静态      更新时间:2023-10-16

我正在阅读有关静态和动态强制转换以及它们之间的差异的信息。它指出

static_cast无法通过虚拟继承进行强制转换,但无论如何动态 铸罐。

如果有人能用一个简单的例子来澄清这意味着什么,我将不胜感激。谢谢

class A {virtual ~A {}}
class B {virtual ~B {}}
class C : A, B {}
C o;
// Now, some implicit conversions:
A& a = c;
B& b = c;
// static casts back:
C& ca = static_cast<C>(a);
C& cb = static_cast<C>(b);
// dynamic casts over the type:
A& ab = dynamic_cast<A>(b);
B& ba = dynamic_cast<B>(a);
动态强制转换

可以跨层次结构进行强制转换(或检查为派生类型),而静态强制转换只能在层次结构中上下转换,除了对象实际属于目标类型之外,静态可证明声音。

在可能的情况下,编译器将动态强制转换减少为静态强制转换以提高效率。

static_cast ,当应用于指针或引用时,允许您以不同的方式处理地址。这适用于单个继承,但不适用于多个继承(无论是否虚拟)。

让我们创建一个没有虚拟继承的简单多重继承。

class A1 {virtual ~A1 {}}
class A2 {virtual ~A2 {}}
class B : public A1, public A2 {virtual ~B {}}

类型 B 的对象可以像这样布置在内存中:

+----------------------+|A1 内存占用量 |+----------------------+|A2 内存占用量 |+----------------------+|B 内存占用 |+----------------------+

让我们创建一个 B 类型的对象和一些指向它的指针。

B b;
B* bPtr = &b;
A1* a1Ptr = bPtr;
A1* a2Ptr = bPtr;

bPtra1Ptr 指向整个B对象的开头。 a2Ptr指向对象的A2部分。

bPtra1Ptr -> +----------------------+         |A1 内存占用量 |a2Ptr -> +----------------------+         |A2 内存占用量 |         +----------------------+         |B 内存占用 |         +----------------------+

现在,如果您决定使用 static_casta1Ptr 获取B*,例如:

B* bPtr2 = static_cast<B*>(a1Ptr);

然后,bPtr2指向整个B对象的开始,这很好,但只是巧合。

bPtr2 -> +----------------------+         |A1 内存占用量 |         +----------------------+         |A2 内存占用量 |         +----------------------+         |B 内存占用 |         +----------------------+

但是,如果您决定使用 static_casta2Ptr 获取B*,它将指向对象的A2部分的开头,这是错误的。

B* bPtr3 = static_cast<B*>(a2Ptr); // Points to the wrong block of memory.
         +----------------------+         |A1 内存占用量 |bPtr3 -> +----------------------+         |A2 内存占用量 |         +----------------------+         |B 内存占用 |         +----------------------+

多个但虚拟继承的对象布局略有不同。

假设您有:

class L1 {virtual ~L1();};
class L2 : public virtual L1 {virtual ~L2();};
class L3 : public virtual L1 {virtual ~L3();};
class L4 : public L2, public L3 {virtual ~L4();};

类型 L4 对象的布局如下所示:

+----------------------+|L1 内存占用量 |+----------------------+|L2 内存占用 |+----------------------+|L3 内存占用 |+----------------------+|L4 内存占用 |+----------------------+

如果您尝试对L2*执行static_castL3*L4*,则很可能会遇到相同类型的问题。

dynamic_cast通过在运行时使用 RTTI 避免了static_cast的问题,并返回正确的地址。