仮想基本クラス


並列的継承の問題点

C++の継承が、いかに柔軟なものかは前回で理解していただけたと思います
ですが、継承によっては非常に難しい問題が発生します
継承が複雑になると、同じクラスを2度継承するという事態が発生します

基本クラス
||
派生クラス1派生クラス2
||
派生クラス3

図を見てわかるように、派生クラス3が基本クラスを2度継承しています
派生クラス1と派生クラス2が、基本クラスを継承しているためです
#include<iostream>
using namespace std;

class Base {
public:
	char *name;
};

class Derived1: public Base {
public:
	int age;
};

class Derived2 : public Base {
public:
	char *sex;
};

class Derived3 : public Derived1 , public Derived2 {
public:
	void print() {
		cout << "名前 : " << name;
		cout << "\t年齢 : " << age;
		cout << "\t性別 : " << sex << '\n';
	}
} obj ;

int main() {
	obj.name = "前原しのぶ";
	obj.age = 13;
	obj.sex = "女";
	obj.print();
	return 0;
}
このプログラムだと、obj.name が非常に曖昧です
Derived1 と Derived2 クラスは、とくに曖昧ではありませんが
Derived3 は、Derived1の基本クラス Base と Derived2 の基本クラス Base を継承します
そのため、このプログラムはコンパイルできません

そこで、仮想基本クラスを用いることでこれを解決します
Base クラスを仮想基本クラスと宣言すると、派生クラスで2度継承する事態を避けられます
これを宣言するには virtual キーワードを用います

virtual [access-specifier] base-class-name

access-specifier には、アクセス指定子を
base-class-name には、仮想基本クラスの名前を指定します

アクセス指定子と virtual の順番は任意です
アクセス指定子が virtual の前にきても、問題はありません
#include<iostream>
using namespace std;

class Base {
public:
	char *name;
};

class Derived1: virtual public Base {
public:
	int age;
};

class Derived2 : virtual public Base {
public:
	char *sex;
};

class Derived3 : public Derived1 , public Derived2 {
public:
	void print() {
		cout << "名前 : " << name;
		cout << "\t年齢 : " << age;
		cout << "\t性別 : " << sex << '\n';
	}
} obj ;

int main() {
	obj.name = "前原しのぶ";
	obj.age = 13;
	obj.sex = "女";
	obj.print();
	return 0;
}
Derived3 が継承した基本クラスは、仮想基本クラスとして Base を継承しています
そのため、Derived3 のオブジェクトは、Base のコピーを一つしか持ちません
こうすることで、このような並列的多重継承を保証することができます

virtual キーワードは、仮想基本クラスを持つ派生クラスからしか意味を持ちません
つまり、上のプログラムの Derived1 や Derived2 からは
継承した Base クラスは通常の基本クラスとして機能します

仮想基本クラスを持つ二つの基本クラスが
それぞれ別のアクセス指定子で継承している場合
派生クラスからアクセス制御は、もっともオープンなアクセス制御を取ります
#include<iostream>
using namespace std;

class Base {
public:
	char *name;
};

class Derived1: virtual public Base {
public:
	int age;
};

class Derived2 : virtual private Base {
public:
	char *sex;
};

class Derived3 : public Derived1 , public Derived2 {
public:
	void print() {
		cout << "名前 : " << name;
		cout << "\t年齢 : " << age;
		cout << "\t性別 : " << sex << '\n';
	}
} obj ;


int main() {
	obj.name = "前原しのぶ";
	obj.age = 13;
	obj.sex = "女";
	obj.print();
	return 0;
}
Derived2 は private で Base クラスを継承していますが
Derived1 は public で Base クラスを継承しています

これらを継承した Derived3 は、Derived1 が public なので
問題なく Base クラスのメンバにアクセスすることができます


virtual

virtual [access-specifier] base-class-name

仮想基本クラスを宣言します
access-specifier - アクセスレベルを定義します。virtual の前でもかまいません
base-class-name - 仮想基本クラスとなるクラスを指定します



前のページへ戻る次のページへ