多重継承
すでにC++の継承という機能を使って、基本クラスを拡張を行えることを学びました。
これまでの例では基本クラスは一つでしたが、C++では複数の基本クラスからひとつの派生クラスを作成することができます。これを多重継承と呼びます。
多重継承を記述する構文は単純で、たとえばbase1、base2という二つのクラスを基本クラスとしてderivedクラスを作成するには、以下のように記述します。
![]()
class derived : public base1, public base2 { ... ... };ここで定義されたderivedクラスのメモリ上のレイアウトは以下のようになり、base1クラスのメンバ、base2クラスのメンバ、そしてderivedクラスで新たに定義されたメンバのすべてが含まれます。
基本クラスをカンマで区切って並べることにより、3つ以上の基本クラスから派生することもできます。
あいまいさとその解決
多重継承を使うことにより複数のクラスの性質を引き継いで新しいクラスを作成することができますが、基本クラスの中でメンバ変数名やメンバ関数名が衝突してしまう場合があります。
class A { public: int foo; }; class B { public: int foo; }; class C : public A, public B { }; void main() { C obj; obj.foo = 10; // <- どちらの foo?? }上記の例では、クラスA,Bを継承してクラスCを定義していますが、クラスA,Bの両方にfooという変数があります。両方を継承してできたクラスCには、fooという名前の変数がふたつ含まれることになります。
main関数内でクラスCのfooにアクセスしようとしていますが、コンパイラはふたつあるうちのどちらのfooにアクセスしてよいかわかりません。
この場合、以下のようにスコープ解決演算子を使い、どちらの基本クラスのメンバかを明示的に示してあげる必要があります。
void main() { C obj; obj.A::foo = 10; // <- 基本クラスAのfooにアクセス }練習問題 4-1
以下のソースは、tunerクラス(チューナー)とcdplayerクラス(CDプレイヤー)から多重継承したjamboxクラス(CDラジカセクラス)を派生する例です。
・プロジェクト p3k3_4、ソースファイル名はp3k3_4.cppとしてビルドして動作を確認しなさい。tunerクラス、cdplayerクラスのメンバが、jamboxクラスに継承されていることを確認しなさい。
・tunerクラス、cdplayerクラス、jamboxクラスのサイズを調べなさい。(sizeof演算子を用いれば良い)
#include <iostream> using namespace std; #pragma pack(1) #pragma pack(show) class tuner { protected: bool power; double freq; public: void turnon() { power = true; } void turnoff() { power = false; } void SetFreq(double f) { freq = f; } double GetFreq() { return freq; } tuner() { cout << "tuner();" << endl; } }; class cdplayer { protected: bool power; int track; public: void turnon() { power = true; } void turnoff() { power = false; } void SetTrack(int t) { track = t; } int GetCurrentTrack() { return track; } cdplayer() { cout << "cdplayer();" << endl; } }; class jambox : public tuner, public cdplayer { protected: int volume; public: void SetVolume(int v) { volume = v; } int GetVolume() { return volume; } jambox() { cout << "jambox();" << endl; } }; void main() { jambox box; box.SetFreq(76.4); box.SetTrack(10); box.SetVolume(100); cout << "freq:"<< box.GetFreq() << " Track #:" << box.GetCurrentTrack() << " Vol:" << box.GetVolume() << endl; //box.turnon(); }練習問題 4-2
4-1で使用されている3つのクラス(tuner, cdplayer, jambox)それぞれにコンストラクタとデストラクタを作成し、それぞれのコンストラクタ、デストラクタの呼び出し順序を確認しなさい。(出力文を記述して確認すればよい。引数はとらなくてよい。)
また、jamboxクラス宣言部の tunerクラス、cdplayer クラスの順序を入れ換えて動作がどのように変化するかを確認しなさい。
class jambox : public cdplayer, public tuner { // <- 順序をいれかえる protected: int volume; ....練習問題 4-3
練習問題 4-1のmain関数の最後にある、box.turnon(); の行のコメントを外してビルドし、どのようなエラーが出るかを確認し、それはなぜかを考察しなさい。
明示的にtunerクラスのturnon関数を呼び出すように修正しなさい。