C++ 重新解释_铸造和交叉铸造 #包括 结构I1 { 虚空nb1()=0; 虚拟~I1(){} }; 结构I2 { 虚空nb2()=0; 虚空nb22()=0; 虚拟~I2(){} }; 结构C12:I1,I2 { virtual void nb1(){std::cout

C++ 重新解释_铸造和交叉铸造 #包括 结构I1 { 虚空nb1()=0; 虚拟~I1(){} }; 结构I2 { 虚空nb2()=0; 虚空nb22()=0; 虚拟~I2(){} }; 结构C12:I1,I2 { virtual void nb1(){std::cout,c++,reinterpret-cast,C++,Reinterpret Cast,由于编译器可能会为C12的两个子对象中的每一个子对象保留一些字节,即使它们没有成员或基类,而且由于这两个子对象的地址是不同的,这可能会导致问题。标准只是说该转换的结果是未指定的(§5.2.10,7).由于编译器可能会为C12的两个子对象中的每一个子对象保留一些字节,即使它们没有成员或基类,而且由于这两个子对象的地址是不同的,这可能会导致问题。标准只是说该转换的结果是未指定的(§5.2.10,7).如果您有一个C12类型的对象x,并且有三个指针指向它,如: #include<iostream

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

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

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

#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;
}
那么指针pA、pB和pC不一定相等。因此,您不能只是在pA、pB和pC之间来回重新解释\u转换。您可以安全地在pA和pB之间以及pA和pC之间进行静态\u转换或动态\u转换。因此,要从I2*获得I1*,您需要先将p2转换为C12*,然后再转换为I1*。选择您最喜欢的行:

C12 x;
C12 *pA = &x;
I1  *pB = &x;
I2  *pC = &x;
I1*p1=static_cast(p2);
I1*p1=动态_型铸造(p2);

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

#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;
}
那么指针pA、pB和pC不一定相等。因此,您不能只是在pA、pB和pC之间来回重新解释\u转换。您可以安全地在pA和pB之间以及pA和pC之间进行静态\u转换或动态\u转换。因此,要从I2*获得I1*,您需要先将p2转换为C12*,然后再转换为I1*。选择您最喜欢的行:

C12 x;
C12 *pA = &x;
I1  *pB = &x;
I2  *pC = &x;
I1*p1=static_cast(p2);
I1*p1=动态_型铸造(p2);

使用
重新解释cast
几乎总是个坏主意

您可以在这里执行
dynamic\u cast
或double
static\u cast
(通过基类)


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

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

现在您得到了指向内部
obj.parent2
的指针,它不是
obj

使用
reinterpret\u cast
几乎总是个坏主意

您可以在这里执行
dynamic\u cast
或double
static\u cast
(通过基类)


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

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

现在您得到了指向内部对象的指针。parent2不是
obj
reinterpreter\u cast
是不安全的;您应该始终使用
dynamic\u cast
I1
I2
是纯虚拟类,这与此无关;
C12
的子对象具有非零存储要求.事实上,在以下计划中:

struct C12 {
    I1 parent1;
    I2 parent2;
};

C12 obj;

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

重新解释强制转换是不安全的;您应该始终使用
动态强制转换。
I1
I2
是纯虚拟类,这与此无关;作为
C12
的子对象,它们具有非零存储要求。事实上,在以下程序中:

struct C12 {
    I1 parent1;
    I2 parent2;
};

C12 obj;
您可能会想到(1.8p5);但这不适用于具有虚拟方法的类,这些类需要vptr

这里是否有使用
重新解释石膏的禁忌症

不要这样做,它会导致未定义的行为

通常,基子对象存储在完整对象中的不同位置,因此cast最终将指向错误的位置。您可能会发现,这些空基类可能(也可能不)最终位于同一位置,因此它“工作”起来是偶然的;但您肯定不能依赖于这种行为

我应该强制使用
dynamic\u cast

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

如果您确实知道常见的派生类型,则可以使用
static\u cast
通过该类型进行转换:

0x14de0c8
0x14de0c8
0x14de0c0   // !!!
nb2         // !!!
I1*p1=static_cast(p2);
请注意,派生类的“向上转换”可以隐式完成;只有基类的“向下转换”需要显式转换

这里是否有使用
重新解释石膏的禁忌症

不要这样做,它会导致未定义的行为

通常,基子对象存储在完整对象中的不同位置,因此cast最终将指向错误的位置。您可能会发现,这些空基类可能(也可能不)最终位于同一位置,因此它“工作”起来是偶然的;但您肯定不能依赖于这种行为

我应该强制使用
dynamic\u cast

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

如果您确实知道常见的派生类型,则可以使用
static\u cast
通过该类型进行转换:

0x14de0c8
0x14de0c8
0x14de0c0   // !!!
nb2         // !!!
I1*p1=static_cast(p2);

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

我不知道您使用的是什么编译器,但您不需要VS2010中的中间步骤。@metalhead:如果您使用的是
静态转换
@CharlesBailey:OP没有提到
静态转换
,而
动态转换则不需要它e> 或者
reinterpret\u cast
@metalhead:但是
reinterpret\u cast
是错误的,并且不起作用(除非你很幸运你的未定义行为),所以在这个答案中只剩下两种可能性。@CharlesBailey:很公平,但有一次VS是未定义的