ダイヤモンド継承によって引き起こされるあいまいさの問題を解決するための仮想継承のプロセスの詳細な分析

 二义性问题请详细看:

http://blog.csdn.net/lxp_mujinhuakai/article/details/69414277 前の記事の問題
解決するには、次のコードを見てください。

#include<iostream>
using namespace std;

class Grandam
{
public:
     void introduce_self()
    {
        cout << "I am grandam." << endl;
    }
};

class Mother :virtual public Grandam
{
public:
    void introduce_self()
    {
        cout << "I am mother." << endl;
    }
};

class Aunt :virtual public Grandam
{
public:
    void introduce_self()
    {
        cout << "I am aunt." << endl;
    }
};

class Daughter :public Mother,public Aunt
{
public:
    void introduce_self()
    {
        cout << "I am daughter." << endl;
    }
};

int main()
{
    Grandam* ptr;
    Daughter d;
    ptr = &d;
    ptr->introduce_self();
    return 0;
}

結果を次の図に示します。

ここに写真の説明を書いてください
オブジェクトのメモリをチェックして、メモリに格納されている特定の番号を知ることができます。

、ptr =&dでポイントを解除し、プログラムがこのポイントまで実行されたら、メモリウィンドウに&dを出力して、図に示すように、オブジェクトd *のメモリを表示できるようにします
ここに写真の説明を書いてください

アドレスはメモリの最初のアドレスに格納されます。このアドレス0x00eadc98をメモリに入力し、図に示すように、このアドレスに格納されている内容を再度確認します。

ここに写真の説明を書いてください

最初の2行の最初の行には、基本クラスに基づく基本クラスオブジェクトのオフセット(0)が格納されていることがわかります。2行目は、基本クラスに基づく派生クラスオブジェクトdのオフセット8を格納します。以下は、仮想継承の特定の実装プロセスをまとめたものです。


オブジェクトは、どのメンバーが呼び出されているかをどのように認識しますか?具体的なプロセスは次のとおりです
。1。ポインターまたは参照は、呼び出したオブジェクトを認識します
。2。オブジェクトは、基本クラスに基づいてオフセットを格納するアドレスを取得できます
。3。アドレスオフセットに基づいて基本クラスを取得します
。4これにより、この基本クラスオブジェクトポインタとオフセットが加算され、呼び出しによって、派生クラスのどのメンバーがどのオブジェクトに対応しているかを区別できます。

注:
1。キーワードvirtualが追加された後、派生クラスオブジェクトにさらに4バイトが割り当てられ、基本クラスのオフセットに基づいてアドレスが格納されます(ステップ2に表示されます)。
2.キーワードvirtualを追加した後、ダイヤモンドの継承サイズは8バイトではなく4バイトになります。基本クラスのメンバーはスペースを開くだけだからです。
3.あいまいさの問題を解決するには、2つの派生クラスが初めて基本クラスを継承するときに、位置の継承メソッドの前にキーワードvirtualを追加する必要があります。

おすすめ

転載: blog.csdn.net/lxp_mujinhuakai/article/details/69427582