C++の仮想継承とダミーベースクラス


昨日の2つの文章「C++のような継承」と「C++の虚関数」は私たちにC++の中のクラスの継承方法と多態の実現を認識させた.今日は、仮想継承と仮想ベースクラスという両者の結合体について学びましょう.
仮想継承とは何かと説明する前に、メモリ内のクラスと親の関係を一気に普及させる必要があります.図1に示すように、各サブクラスはメモリに親メモリのコピーを1部持っている.
図1サブクラスと親クラスのメモリ内の関係
子オブジェクトが使用するメモリは、親オブジェクトが使用するメモリよりも常に大きくなります.子オブジェクトは親を継承し、親メソッドインタフェースも継承するため、子オブジェクトに親オブジェクトのメモリコピーがあります.
次に単一継承と菱形継承についてお話しします.
1)単一継承とは、図2に示すように、各サブクラスに親が1つしかないことを意味する.単一継承メモリ関係を図3に示す.
 
                                              
図2単一継承図3単一継承メモリ関係
2)菱形継承とは、1つのクラスの2つの親に共通の親があることを意味する.図4に示すように.菱形継承のメモリ関係を図5に示す.
                  
図4菱形継承図5菱形継承のメモリ関係
菱形の継承を見たとき、少し問題があったのではないでしょうか.第一に、クラスCにはクラスAのそっくりなコピーが2部含まれている.第二に、クラスAのコンストラクタは2回繰り返し呼び出される.読者が信じない場合は、次のコードを試してみてください.
 
   
#include    
using namespace std;   
 
   
class A  
{  
public:  
    A(){cout<This is A constructor."< 
   
    ~A(){cout<This is A destructor."< 
   
    void speak(){cout<This is A speak!"< 
   
};  
  
class B1: public A 
{  
 public:  
     B1(){cout<This is B1 constructor."< 
   
    ~B1(){cout<This is B1 destructor."< 
   
};  
 
   
class B2: public A 
{  
public:  
    B2(){cout<This is B2 constructor."< 
   
    ~B2(){cout<This is B2 destructor."< 
   
};  
  
class C:public B1,public B2  
{  
public:  
    C(){cout<This is C constructor."< 
   
    ~C(){cout<This is C destructor."< 
   
}; 
 
   
int main()   
{   
    C *c=new C(); 
    //c->speak(); 
    delete c; 
    return 0;   
}
プログラムの は の りです.
コードに「c->speak();」というコードを すると、コンパイラはまたエラーを します.エラーメッセージは のとおりです.
Error    1    error C2385: ambiguous access of 'speak'    e:\XXX\main.cpp 38これはクラスB 1とクラスB 2の に speak()があり、コンパイラがどちらを すべきか からないため、ここでは が じる.
、 は に3つの について べた.
  • ストレージの :より くのストレージ を しています.
  • :ベースクラスの (プロファイル) が び された.
  • のコンパイル:ベースクラスのメンバー を び すと、 が されます.


  • 、いよいよバーチャル の です! は ですが、ベースクラスの にvirtualキーワードを します. のコードは のとおりです.
     
       
    #include    
    using namespace std;   
     
       
    class A  
    {  
    public:  
        A(){cout<This is A constructor."< 
       
        ~A(){cout<This is A destructor."< 
       
        void speak(){cout<This is A speak!"< 
       
    };  
      
    class B1: public virtual A 
    {  
     public:  
         B1(){cout<This is B1 constructor."< 
       
        ~B1(){cout<This is B1 destructor."< 
       
    };  
     
       
    class B2: virtual public A 
    {  
    public:  
        B2(){cout<This is B2 constructor."< 
       
        ~B2(){cout<This is B2 destructor."< 
       
    };  
      
    class C:public B1,public B2  
    {  
    public:  
        C(){cout<This is C constructor."< 
       
        ~C(){cout<This is C destructor."< 
       
    }; 
     
       
    int main()   
    {   
        C *c=new C(); 
        c->speak(); 
        delete c; 
        return 0;   
    }

    キーワードvirtualの に してください.このとき、プログラムを した 、 のようになります.
    たでしょう、class Aのコンストラクション は1 しか されず、speak() は に され、 は しません. に されたベースクラスは、 のプログラムのclass Aのような ベースクラスであることを れました.
    は と をまとめました. があれば、コメントを します.
    ありがとうございます:《C++プログラミングの な --プログラマーの ガイド》