2013年12月11日水曜日

C++ 多重継承

複数の基底クラスから一つの派生クラスを作ることができます。
これを多重継承といいます。(^^)
一方、一つの基底クラスから派生クラスを作ることを単一継承といいます。

多重継承の一例です。

Copyクラス Scannerクラス  Printerクラス Faxクラス
 Copy()         Scan()            Print()          Fax()
  Switch()       Switch()          Switch()        Switch()
 |_____|______|____|
               |
              MFPクラス

MFPとは、MultiFunctionPrinter Pは Procduct ということも...
要は複合機です。

MFPクラスは、他のクラスのメンバをすべて含んでいます。
すなわち、MFPクラスからCopyクラスに定義してある関数が
使用できるということになります。(^^)

多重継承の定義の仕方
多重継承の定義は、基底クラスを「, (カンマ)」で区切って記述します。

class MFP : public Copy, public Scanner, public Printer, public Fax
{
    :
    :
};

多重継承はメンバが曖昧になる
多重継承で、もし複数の基底クラスに同じ名前のメンバがあった場合、
派生クラスには同じ名前のメンバが複数出来てしまうことになります。

先の例では、すべてのクラスに 関数 Switch() があるため、
MFPクラスでは、4つの Switch()が出来るのです(^^;)

派生クラスからこれらの重複したメンバにアクセスするには、
スコープ解決演算子を使います。

class Copy
{
public:
    int GetSwitchStat(void) { return m_on; }
    void SetSwitch(int n) { m_on = n; };  //Copyクラスのメンバ関数SetSwitch()
private:
    int m_on;
};

class Scanner
{
public:
    int GetSwitchStat(void) { return m_on; }
    void SetSwitch(int n) { m_on = n; };  //Scannerクラスのメンバ関数SetSwitch()
private:
    int m_on;
};

class Printer
{
public:
    int GetSwitchStat(void) { return m_on; }
    void SetSwitch(int n) { m_on = n; };  //Printerクラスのメンバ関数SetSwitch()
private:
    int m_on;
};

class Fax
{
public:
    int GetSwitchStat(void) { return m_on; }
    void SetSwitch(int n) { m_on = n; };  //Faxクラスのメンバ関数SetSwitch()
private:
    int m_on;
};

class MFP : public Copy, public Scanner, public Printer, public Fax
{
public:
    int GetSwitchStat(void) { return m_on; }
private:
    int m_on;
};

int main(void)
{
    MFP mfp;
    mfp.SetSwitch(0);  //MFPクラスのオブジェクトからメンバ関数を呼び出す?
        :

これではコンパイラはどのSetSwitch()を使うか判断できません。
そのため、コンパイルエラーになります。(*´Д`)

# g++ -g -Wall -o test test.cpp
test.cpp: In function ‘int main()’:
test.cpp:52:9: error: request for member ‘SetSwitch’ is ambiguous
test.cpp:36:10: error: candidates are: void Fax::SetSwitch(int)
test.cpp:27:10: error:                 void Printer::SetSwitch(int)
test.cpp:18:10: error:                 void Scanner::SetSwitch(int)
test.cpp:9:10: error:                 void Copy::SetSwitch(int)
r
同名のメンバがあるときは、スコープ解決演算子を使って、
どのクラスのメンバを呼び出すのかを指定してください。

int main(void)
{
    MFP mfp;
    mfp.Fax::SetSwitch(0);  //Faxクラスの

    cout << "MFP switch1 " << mfp.Fax::GetSwitchStat() << endl;
    cout << "MFP switch2 " << mfp.GetSwitchStat() << endl;
        :

# ./test
MFP switch1 0
MFP switch2 34332

この例では、MFPクラスの m_on には値を設定していないので
不定値が出力されています。
このことからも、多重継承によって、メンバ変数 m_on が
5つあるということがわかります。(^^;)
 
今日の名言
明朗になろう。耐え切れぬほどひどい不幸など、ありえないのだから。
                             ジェイムズ・ラッセル・ローウェル

私はあきれ返った楽天家として通っているが、まさにそのとおりである。私は成功のこと
ばかり考え、決して失敗のことを考えないからだ。こうして、知らず知らずのうちに不幸に
背を向け、失敗を恐れる気持ちを消し去る。私はこうして自分の人生哲学を実行している。
どんな仕事も必ず十分に検討して、自分の力でやれるのはどの程度か、はっきり見極める
ことだ。それからこの目標をどうやって遂行するか計画を立てる。その際、他人の方法を
真似てはいけない、自分独自の方法を考え出して計画することだ。
                             フェルディナンド・フォシュ将軍

私たちの疲労は仕事によって生じたのではなく、悩み、挫折、後悔が
原因となっていることが多い。
                             デール・カーネギー