27.1 クラス継承の基礎
/* 基底クラスと派生クラス */
/* privateなメンバを継承する */
/* protectedメンバを使う */
/* 基底クラスのコンストラクタを使う */
class ClsXY : public ClsX {
...
ClsXY(int n1 = 0, int n2 = 0); // コンストラクタ宣言
...
};
ClsXY::ClsXY(int n1, int n2) // コンストラクタ定義
{
setX(n1); // 基底クラスClsXのxを設定
y = n2;
}
基底クラスのメンバを初期化するためにsetX(n1)を記述しています。
これは、個別に設定するのではなく、
基底クラスのコンストラクタを呼び出すという方法で簡単に記述できます。
ClsXY::ClsXY(int n1, int n2) : ClsX(n1)
{
y = n2;
}
/* 名前の隠ぺいとスコープ解決 */
ClsXY a(10, 20); // 派生クラスを宣言
a.dispX(); // 基底クラスのdispX()関数を使う
a.dispXY(); // 派生クラスのdispXY()関数を使う
ここでもし、両関数ともdispという同じ関数名にしたらどうなるでしょうか。
たとえば、
ClsXY a(10, 20); // 派生クラスを宣言
a.disp(); // 自分(派生クラス)のdisp()関数を使用する
a.ClsX::disp(); // 基底クラスのdisp()関数を使用する
/* 継承時のアクセス指定子 */
class clsA { ~ }; // 基底クラス
class clsB : public clsA { ~ }; // publicで継承
class clsB : protected clsA { ~ }; // protectedで継承
class clsB : private clsA { ~ }; // privateで継承
class clsB : clsA { ~ }; // 同上。デフォルトでprivateになる
struct clsB : public clsA { ~ }; // publicで継承
struct clsB : clsA { ~ }; // 同上。デフォルトでpublicになる
(0)privateメンバはいかなる継承をしてもprivateのままである
(1)publicで継承したときは、基底クラスのアクセス指定子が、そのまま引き継がれる
基底クラスのpublicは派生クラスでpublicのままである
基底クラスのprotectedは派生クラスでprotectedのままである
(2)privateで継承したときは、基底クラスのアクセス指定子がprivateに解釈される
基底クラスのpublicは派生クラスでprivate扱いになる
基底クラスのprotectedは派生クラスでprivate扱いになる
(3)protectedで継承したときは、基底クラスのアクセス指定子がprotectedに解釈される
基底クラスのpublicは派生クラスでprotected扱いになる
基底クラスのprotectedは派生クラスでprotectedのままである
/* 継承時のアクセス指定子の機能比較 */
27.2 クラス継承の種類
/* クラス継承図 */
省略
/* 単独継承と直接継承と間接継承 */
省略
/* 多重継承 */
class ClsA {
...
}
class ClsB {
...
}
class ClsAB : public ClsA, public ClsB {
...
}
/* 多重基底クラスと仮想基底クラス */
class ClsA { ... };
class ClsB : public ClsA { ... };
class ClsC : public ClsA { ... };
class ClsD : public ClsB, public ClsC { ... };
一見してこの継承には問題があります。
それはClsDの中に、ClsAのオブジェクトがふたつもあることです。
この問題を解決するために、仮想基底クラス
という機能が用意されています。
仮想基底クラスは次のようにvirtual指定子を使って指定します。
class ClsA {
...
};
class ClsB : virtual public ClsA { // ClsAを仮想基底クラスとして継承
...
};
class ClsC : virtual public ClsA { // ClsAを仮想基底クラスとして継承
...
};
class ClsD : public ClsB, public ClsC {
...
};
このようにして派生したClsDには、ClsAオブジェクトがひとつだけ含まれることになります。
27.3 仮想関数
/* 継承クラス間のポインタ変換 */
class ClsB : public ClsA { ... };
ClsA aa, *pa;
ClsB bb, *pb;
pa = &aa; // OK
pb = &bb; // OK
pa = &bb; // OK
pb = &aa; // NG
pa = pb; // OK
pb = pa; // NG
/* 継承クラス間の参照変換 */
/* 静的結合と動的結合 */
省略
/* 仮想関数の機能 */
/* 純粋仮想関数 */
/* 抽象クラス */
省略
/* 関数のオーバーロードとオーバーライド */
省略