p632〜p639まで

ついに13章。多分この章が一番アツい。

多重継承

多重継承を扱う場合、一番大本の基底クラスを一次クラス、それを継承したクラスを二次クラス、さらにその二次クラス同士を継承したクラスを三次クラスとして話を進めます。
コード的にはこんな感じ。(各Hogeサフィックスが何次クラスに対応しているか示している)

class Hoge1
{
public:
  virtual void Foo() = 0;
};

class Hoge2_1
{
public:
  virtual void Foo(){ do something... }
};

class Hoge2_2
{
public:
  virtual void Foo(){ do something... }
};

class Hoge3 : public Hoge2_1, public Hoge2_2
{
};

それではまとめ。

・二次クラスで一次クラスのインタフェースをオーバーライドした時の三次クラスでのその関数の呼び出し方。

Hoge3 hoge3;

// アップキャストして呼び出す方法
Hoge2_1& hoge2_1 = hoge3;
Hoge2_2& hoge2_2 = hoge3;
hoge2_1.Foo(); // Hoge2_1のFooが呼ばれる
hoge2_2.Foo(); // Hoge2_2のFooが呼ばれる

// スコープ解決演算子を用いる方法
// こっちもご想像のとおり。
hoge3.Hoge2_1::Foo();
hoge3.Hoge2_2::Foo();


・一次クラスのインタフェースを二次クラスでオーバーライドし、三次クラスでもオーバーライドした場合の関数呼び出し。

class Hoge3 : public Hoge2_1, public Hoge2_2
{
public:
  virtual void Foo() { do something... }
};

// proc
Hoge3 hoge3;

// アップキャストして呼び出す方法
Hoge2_1& hoge2_1 = hoge3;
Hoge2_2& hoge2_2 = hoge3;
hoge2_1.Foo(); // Hoge3のFooが呼ばれる(Hoge2_1のFooがオーバーライドされている)
hoge2_2.Foo(); // Hoge3のFooが呼ばれる(Hoge2_2のFooもオーバーライドされている)

// スコープ解決演算子を用いる方法
hoge3.Hoge2_1::Foo(); // Hoge2_1のFooが呼ばれる
hoge3.Hoge2_2::Foo(); // Hoge2_2のFooが呼ばれる

このことから、仮想関数の呼びわけにはスコープ解決演算子を使わないほうがいいことがわかる。


・一次クラスにアップキャストする場合は、一旦二次クラスへ明示的にアップキャストを行わなければならない。(どちら由来の一次クラスかわからないため)


うーん、これの最後の部分をみてちょっと思ったのは、菱形継承っていう言葉はあんまり使わないほうがいいのかなーということ。というのも、どちら由来の、というところがやっぱり重要なので。多分、菱形継承っていう言い方は実装の継承に由来するのかなーとか思ったり。まぁ実装の継承、インタフェースの継承っていう言葉は最近覚えたばっかりなんで間違ってるかもしれませんが!
ああ、でも結局実装の継承が行われる場合は菱形継承って言うことになるのか。

ぜんぜん違うっすね><っていうか、今回の場合は菱形継承じゃない><><>
結局、菱形継承かどうかっていうのは継承元のインスタンスを共有してるかどうかってところですね><
戒めとして残しておこう。

次は仮想継承。キリがいいので今日はこんなところで。残り時間で明日の分もちょっと勉強しとこう。