C++ c++;多重继承-编译器修改我的指针

C++ c++;多重继承-编译器修改我的指针,c++,multiple-inheritance,unions,C++,Multiple Inheritance,Unions,如果我运行以下代码,我会打印出不同的地址。为什么? class Base1 { int x; }; class Base2 { int y; }; class Derived : public Base1, public Base2 { }; union U { Base2* b; Derived* d; U(Base2* b2) : b(b) {} }; int main() { Derived* d = new Derived;

如果我运行以下代码,我会打印出不同的地址。为什么?

class Base1 {
    int x;
};

class Base2 {
    int y;
};

class Derived : public Base1, public Base2 {

};

union U {
    Base2* b;
    Derived* d;
    U(Base2* b2) : b(b) {}
};

int main()
{
    Derived* d = new Derived;

    cout << d << "\n";
    cout << U(d).d << "\n";

    return 0;
}
另外,如果任何一个基类都为空,问题就会消失。 这是一个编译器错误吗?我想让它把我的指针留在地狱里

如果我运行以下代码,我会打印出不同的地址。为什么?

class Base1 {
    int x;
};

class Base2 {
    int y;
};

class Derived : public Base1, public Base2 {

};

union U {
    Base2* b;
    Derived* d;
    U(Base2* b2) : b(b) {}
};

int main()
{
    Derived* d = new Derived;

    cout << d << "\n";
    cout << U(d).d << "\n";

    return 0;
}
因为
Derived
对象的
Base2
子对象不在
Derived
对象的开头。所以地址不同。当编译器执行从
派生*
Base2*
的隐式强制转换时,它需要调整地址

根据
Base1
Base2
类的定义,
派生的
类的两个子对象不可能位于
派生的
对象的起始地址-在该地址没有空间容纳两个子对象

假设您有以下代码:

Derived* d = new Derived;

Base1* pb1 = d;
Base2* pb2 = d;
pb1
pb2
如何指向同一地址
pb1
必须指向
Base1::x
项,
pb2
必须指向
Base2::y
项(这些项必须是不同的)

更有趣的是,如果你反复进出工会,地址会不断增加4

因为你是在写了
b
成员之后从工会的
d
成员那里读的,这是一种未定义的行为(你基本上是在
Base2*
上执行类似于
reinterpret\u cast()

我想让它把我的指针留在地狱里


如果需要
Base2*
指针,则不需要。多重继承使事情变得更加复杂——这就是为什么许多人建议除非绝对必要,否则不要使用多重继承。

联合构造函数从不初始化成员d

union构造函数有一个错误,它没有用参数b2初始化成员b,而是用自身初始化b

// b(b) should probably be b(b2)
U(Base2* b2) : b(b) {}
当您的第一个主函数示例尝试构造U的实例并打印成员d时,它实际上正在打印一个未定义的值,因为成员d尚未初始化,并且不能保证可以访问

// U(d) doesn't construct member d, so .d returns an undefined value
cout << U(d).d << "\n";
//U(d)不构造成员d,因此.d返回一个未定义的值

不能不使用多重继承不会使这个问题消失;如果基类没有虚函数,而您在派生类中引入它们,同样的事情也会发生。更重要的是,这是未定义的行为,故事到此结束……好吧,我不想从联合中获取Base2指针,所以问题出在联合构造函数中,因为我正在初始化Base2指针,它会被调整。如果我使用void*指针,那么它只会强制编译器保留我给它的地址。
// U(d) doesn't construct member d, so .d returns an undefined value
cout << U(d).d << "\n";
// d is set to a newly constructed instance of Derived
Derived* d = new Derived;

// current address of d is printed
cout << d << "\n";

// a new instance of U is constructed. The address of member d will be in close
// proximity to the newly initialized U instance, and is what will be printed
d = U(d).d;
cout << d << "\n";

// yet another new instance of U is constructed, and again, the address of member
// d will be in close proximity to the newly initialized U instance, and is
//what will be printed
d = U(d).d;
cout << d << "\n";