虚拟多重继承和指针

时间:2013-04-13 04:43:02

标签: c++

给定以下类层次结构:

class A {
int x;
public:
A(int X) : x(X) {}
void setX(int x) { this->x = x; }
};



class B : public virtual  A {
int y;
public:
B(int X, int Y) : A(X), y(Y) {}
};

class C : public virtual A {
int z;
public:
C(int X, int Z) : A(X), z(Z) {}
};

class D : public C, public B {
public:
D(int x, int y, int z) : A(x), C(x,z), B(x,y) {}
};

以及以下主要内容:

int main (void)
{
D x(2,3,4);
A* temp1 = &x;
B* temp2 = &x;
C* temp3 = &x;
}

似乎temp1,temp2和temp3都指向不同的地址.. B和C不应该共享同一个A对象吗? 毕竟,每个C和B对象都是A,所以指针应首先“看到”A对象..不是吗? 另外,C指针包含X的地址..这是一个D对象。为什么呢?

这是内存映射:

&x      0x0036f828 {...}    D *
temp1   0x0036f838 {x=5 }   A *
temp2   0x0036f830 {y=3 }   B *
temp3   0x0036f828 {z=4 }   C *

3 个答案:

答案 0 :(得分:0)

你是对的,因为B和C需要共享同一个A对象。而这正是这里会发生的事情。您看到的地址实际上是每个类唯一的虚拟表的地址。在虚拟继承的情况下,每个类的虚拟表将具有指向虚拟基类的指针,在本例中为对象A.

因此,B类和C类的虚拟表都有一个指针,每个指针都指向对象A的相同地址。

答案 1 :(得分:0)

这就是对象represented in memory的方式。

所以你的对象看起来像这样:

+ 0x0036f828
- D
- int z (C)
- int y (B) 
- int x (A)

C ++ cast只是给出了对象开头的偏移量 因此,您可以看到偏移量只是类 A,B,C 的整数大小(因为它是它们包含的内容)和类 B,C 。
并且 D 没有成员,因此其偏移量为0。

请注意,C ++编译器按实际编写成员和基类的顺序设置内存布局。

因此,如果你改变D中基类的顺序,那么你会得到不同的结果:

class D : public B, public C

现在 B 将是D。

之后布局中的第一个类

答案 2 :(得分:0)

如果使用普通结构写出来,这就是看起来的样子:

struct A {
  int x;
};

struct B {
  A *ap;
  int y;
};

struct C {
  A *ap;
  int z;
};

struct D {
  C c;
  B b;
  A a;
};

int main (void)
{
  D x;
  A* temp1 = &x.a;
  B* temp2 = &x.b;
  C* temp3 = &x.c;
}

由于BC使用虚拟不一致,它们只包含指向基础的指针,而不是实际对象。您可以看到c位于D的开头,因此它们将具有相同的地址。