1
#include<iostream>

struct I1
{ 
    virtual void nb1()=0;
    virtual ~I1(){}
};

struct I2
{ 
    virtual void nb2()=0;
    virtual void nb22()=0;
    virtual ~I2(){}
};

struct C12 : I1, I2
{
    virtual void nb1(){std::cout << "nb\n";}    
    virtual void nb2(){std::cout << "nb2\n";}    
    virtual void nb22(){std::cout << "nb22\n";}
};

int main()
{
    I2 * p2 = new C12; 
    I1 * p1 = reinterpret_cast<I1*>(p2);
    return 1;
}

在这里使用 a 有什么禁忌reinterpret_cast吗?我应该强制使用dynamic_cast吗?

只有 I1 和 I2 是纯虚拟的才可以吗?

4

5 回答 5

3

reinterpret_cast不安全;你应该总是使用dynamic_cast. I1并且I2是纯虚类是无关紧要的;作为它们的子对象,C12它们具有非零存储要求。实际上,在以下程序中:

int main() {
    I2 * p2 = new C12; 
    I1 * p1 = reinterpret_cast<I1*>(p2);
    std::cout << p2 << '\n';
    std::cout << p1 << '\n';
    std::cout << dynamic_cast<I1*>(p2) << '\n';
    p1->nb1();
}

输出是:

0x14de0c8
0x14de0c8
0x14de0c0   // !!!
nb2         // !!!

你可能会想到空基优化(1.8p5);但这不适用于具有需要 vptr 的虚拟方法的类。

于 2013-04-16T12:11:14.433 回答
3

在这里使用 a 有什么禁忌reinterpret_cast吗?

不要那样做;它会给出未定义的行为。

通常,基本子对象存储在完整对象内的不同位置,因此演员表最终会指向错误的位置。您可能会偶然发现它对这些空基类“起作用”,因为它们可能(或可能不会)最终位于同一位置;但你当然不能依赖这种行为。

我应该强制使用dynamic_cast吗?

如果您在编译时不知道通用派生类型 ( C12),那么这是唯一明智的选择。请注意,它需要多态类(这里就是这种情况)。

如果您确实知道常见的派生类型,那么您可以使用以下方法进行转换static_cast

I1 * p1 = static_cast<C12*>(p2);

请注意,派生类的“向上转换”可以隐式完成;只有基类的“向下转型”需要显式转型。

于 2013-04-16T12:11:38.727 回答
1

由于编译器可能会为 C12 的两个子对象中的每一个保留一些字节,即使它们没有成员或基类,并且从那时起这两个子对象的地址是不同的,这可能会导致问题。该标准只是说该演员的结果是未指定的(§5.2.10,7)。

于 2013-04-16T11:57:45.570 回答
0

如果你有一个 C12 类型的对象 x 并且有三个指向它的指针,如下所示:

C12 x;
C12 *pA = &x;
I1  *pB = &x;
I2  *pC = &x;

那么指针 pA、pB 和 pC 不一定相等。所以你不能只是在 pA、pB 和 pC 之间来回重新解释。您可以安全地在 pA 和 pB 之间以及 pA 和 pC 之间进行 static_cast 或 dynamic_cast。因此,要从 I2* 获得 I1*,您需要先将 p2 转换为 C12*,然后再转换为 I1*。选择你最喜欢的线路:

I1 * p1 = static_cast<C12*>(p2);
I1 * p1 = dynamic_cast<C12*>(p2);
于 2013-04-16T11:59:47.267 回答
0

使用 . 几乎总是坏主意reinterpret_cast

在这里你可以做一个dynamic_cast或两个static_cast(通过基类)。


从 ABI 的角度来看,您C12是:

struct C12 {
    I1 parent1;
    I2 parent2;
};

C12 obj;

现在您已经获得了指向 inner的指针obj.parent2,但不是obj.

于 2013-04-16T12:04:02.553 回答