C++オブジェクトモデル5——オブジェクトの構造/構造

1986 ワード

オブジェクトの構造/構造順序
  • ダミーベースクラスを初期化し、継承順に左から右、最深から最浅に変更します.
  • 初期化親が継承順に初期化され、親に親がある場合は、再帰的に親の親が初期化されます.
  • 虚関数テーブルと虚関数ポインタを初期化します.
  • 初期化リストのメンバーは宣言順に初期化され、メンバーが初期化リストに含まれていない場合はデフォルトの初期化構造を使用して初期化されます.
  • は、ユーザの初期化コードを実行する.

  • 初期化順序から2つの点がわかります:1、ユーザーが自分の初期化コードでmemcpy関数を使用している場合、虚関数ポインタを破壊し、プログラムの実行エラーを引き起こす可能性があります.2、親のコンストラクション関数で虚関数を呼び出すと、親の虚関数しか実行できず、子の虚関数を呼び出すことができません.このときの虚関数ポインタは親の虚関数数を指しているため、子の虚関数テーブルはまだ構築されていません.
    #include
    using namespace std;
    
    class A1{
    public:
        A1(int val){
            cout << "A1()" << endl;
        }
        ~A1(){
            cout << "~A1()" << endl;
        }
    };
    
    class A2{
    public:
        A2(int val){
            cout << "A2()" << endl;
        }
        
        ~A2(){
            cout << "~A2()" << endl;
        }
    };
    
    class B1 :public A1{
    public:
        B1():A1(0){
            cout << "B1()" << endl;
        }
    
        ~B1(){
            cout << "~B1()" << endl;
        }
    };
    
    class B2 :virtual public A2{
    public:
        B2():A2(0){
            cout << "B2()" << endl;
        }
    
        ~B2(){
            cout << "~B2()" << endl;
        }
    };
    
    class C :public B1, public B2{
    public:
        C():A2(0){
            cout << "C()" << endl;
        }
        ~C(){
            cout << "~C()" << endl;
        }
    };
    
    int main(){
        C *c = new C();
        delete c;
        return 0;
    }
    

    このコードは主に2つのことを説明したいと思っています.1、虚継承では、虚ベースクラスの初期化はサブクラスによって初期化されるべきです.複数の親が同じ虚ベースクラスを継承する場合があるため、虚ベースクラスの初期化には曖昧さがあります.2、初期化親は順番に初期化されますが、ダミーベースクラスは優先的に初期化されます.また,マルチ継承ではthisポインタ調整が発生することに注意すべきである.
    オブジェクトの架空の順序は、スタックの操作のように、スタックに入る順序とスタックを出る順序が正反対であることも理解しやすい.すなわち,析出の順序は次のとおりである.
  • は、ユーザのコードを実行する.
  • は、宣言された順序とは逆の順序でオブジェクトメンバーの構造関数を呼び出す(存在する場合).
  • 虚関数ポインタを再設定し、サブクラスの虚関数テーブルを指すようにします.
  • は、宣言順序とは逆の順序で親クラスのプロファイルを再帰的に呼び出す関数である.
  • は、仮想ベースクラスの構造関数を逆の順序で呼び出す.