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

时间:2014-04-02 18:06:57

标签: c++ dynamic-cast static-cast

我正在阅读静态和动态演员以及他们之间的差异。 它说明了

  

static_cast不能通过虚拟继承来强制转换   演员可以。

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

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:1)

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

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

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

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

+----------------------+
| A1 memory footprint  |
+----------------------+
| A2 memory footprint  |
+----------------------+
| B  memory footprint  |
+----------------------+

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

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

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

bPtr
a1Ptr -> +----------------------+
         | A1 memory footprint  |
a2Ptr -> +----------------------+
         | A2 memory footprint  |
         +----------------------+
         | B  memory footprint  |
         +----------------------+

现在,如果您决定使用static_castB*获取a1Ptr,例如:

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

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

bPtr2 -> +----------------------+
         | A1 memory footprint  |
         +----------------------+
         | A2 memory footprint  |
         +----------------------+
         | B  memory footprint  |
         +----------------------+

但是,如果您决定使用static_castB*获取a2Ptr,则会指向对象的A2部分的开头,错。

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

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

说你有:

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 memory footprint  |
+----------------------+
| L2 memory footprint  |
+----------------------+
| L3 memory footprint  |
+----------------------+
| L4 memory footprint  |
+----------------------+

如果您尝试在static_castL2*L3*上执行L4*,则很可能遇到相同类型的问题。

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