C++の仮想継承とダミーベースクラス
6769 ワード
昨日の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回繰り返し呼び出される.読者が信じない場合は、次のコードを試してみてください.
仮想継承とは何かと説明する前に、メモリ内のクラスと親の関係を一気に普及させる必要があります.図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++プログラミングの な --プログラマーの ガイド》