簡體   English   中英

虛擬多重繼承和指針

[英]Virtual multiple inheritance and pointers

給定以下類層次結構:

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 *

您說對了,B和C需要共享同一個A對象。 這就是這里會發生的情況。 您看到的地址實際上是每個類唯一的虛擬表的地址。 在虛擬繼承的情況下,每個類的虛擬表將具有一個指向虛擬基類的指針,在本例中為對象A。

因此,類B和類C的虛擬表都將具有一個指針,每個指針指向對象A的相同地址。

這只是對象在內存中表示的方式。

因此,您的對象如下所示:

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

C ++轉換僅給出對象開始的偏移量。
所以,你可以看到,偏移量為類A整數只是大小,B,C(因為這是它們所包含的)和B,C的虛擬表。
而且D沒有成員,因此其偏移量為0。

請注意,C ++編譯器按照實際編寫成員和基類的順序設置內存布局。

因此,如果您要更改D中基類的順序,則會得到不同的結果:

class D : public B, public C

現在B將成為D之后的布局中的第一類。

如果使用普通結構將其寫出,則可能是這樣:

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使用虛擬繼承,它們僅包含指向基址的指針,而不包含實際對象。 您會看到,由於cD的開頭,所以它們將具有相同的地址。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM