多重継承削除問題の解決

3753 ワード

//
class A 
{
public:
int a;
};

class B
{
public:
float c;
};

//     
class D : public A, public B
{
};

//
main ()
{
    B* pB = new D;
    delete pB;
}

上のコードは実行時にクラッシュします.
理由は次のとおりです.
C++コンパイラ内部の組織:(D)
|---------------------------------|
|     ----------------------           |
|    |            A                 |         |
|     ----------------------           |
|                                               |
|   --------------------------        |
|   |              B                  |        |
|   --------------------------        |
|                                               |
|                  D                           |
|----------------------------------|
 
A、Bのメモリレイアウトは継承順に並べられていますが、私の上の例では、まずpublic A、それからpublic Bなので、上のメモリレイアウトになります.
例では、B*pB=new Dを使用します.
そしてdelete pB;
削除を行うと、コンパイラはBのメモリを削除します.Bは実際にはDを指しているので、Dのメモリを削除します.しかし、メモリレイアウトはAが前に並んでいるのでsizeof(B)バイトのAメモリを削除し、プログラムがクラッシュした.
 
この問題を解決するために,Bに純虚関数,Release()=0を加えることができた.親がそれを実現すれば、それ自体を削除するために使用されます.正しいメモリアドレスと解放するメモリサイズを指すことができます.
コードは次のとおりです.
class A
{
public:
int a;
};

class B
{
public:
virtual void Release () = 0;
int b;
};

class D : public A, public B
{
public:
   //      
   virtual void Release () {delete this;};
};

main ()
{
    B* pB = new D;
    pB->Release ();
}