C++ では、継承は、派生のメカニズムによって実現されます。
派生を使用すると、派生クラス
と呼ばれるクラスを、基底クラス と呼ばれる別のクラスから派生させることができます。
構文 - 派生クラスの派生 >>-derived_class--:---------------------------------------------> .-,---------------------------------------------------------. V | >----+----------------------------+--qualified_class_specifier-+->< +-virtual--+-----------+-----+ | +-public----+ | | +-private---+ | | '-protected-' | '-+-public----+--+---------+-' +-private---+ '-virtual-' '-protected-'
派生クラスの宣言の中で、派生クラスの基底クラスをリストします。 派生クラスは、これらの基底クラスからそのメンバーを継承します。
qualified_class_specifier は、クラス宣言で事前に宣言されているクラスである必要があります。
アクセス指定子 は、public、private、または protected のいずれかです。
virtual キーワードは、仮想基底クラスの宣言に使用できます。
次の例は、派生クラス D と、基底クラス V、B1、 および B2 の宣言を示しています。 クラス B1 は、クラス V から派生し、D の基底クラスなので、 基底クラスでもあり派生クラスでもあります。
class V { /* ... */ }; class B1 : virtual public V { /* ... */ }; class B2 { /* ... */ }; class D : public B1, private B2 { /* ... */ };
宣言されているが定義されていないクラスは、基底リストに入れることができません。
次に例を示します。
class X; // error class Y: public X { };
コンパイラーは、X が定義されていないので、 クラス Y の宣言を許可しません。
クラスを派生させると、派生クラスは、基底クラスのクラス・メンバーを継承します。 継承されたメンバー (基底クラスのメンバー) は、派生クラスのメンバーと同様に参照することができます。 次に例を示します。
class Base { public: int a,b; }; class Derived : public Base { public: int c; }; int main() { Derived d; d.a = 1; // Base::a d.b = 2; // Base::b d.c = 3; // Derived::c }
派生クラスには新しいクラス・メンバーを追加したり、既存の基底クラス・メンバーを再定義することもできます。 上記の例では、派生クラスのメンバー c に加えて、 派生クラス d の 2 つの継承されたメンバー a および b に値が代入されます。 派生クラスの中で基底クラスのメンバーを再定義しても、:: (スコープ・レゾリューション) 演算子を使用すれば、依然として基底クラスのメンバーを参照することができます。 次に例を示します。
#include <iostream> using namespace std; class Base { public: char* name; void display() { cout << name << endl; } }; class Derived: public Base { public: char* name; void display() { cout << name << ", " << Base::name << endl; } }; int main() { Derived d; d.name = "Derived Class"; d.Base::name = "Base Class"; // call Derived::display() d.display(); // call Base::display() d.Base::display(); }
次に、上記の例の出力を示します。
Derived Class, Base Class Base Class
派生クラスのオブジェクトは、基底クラスのオブジェクトと同様に操作できます。 派生クラスのオブジェクトに対するポインターや参照を、 その基底クラスに対するポインターや参照の代わりに使用することができます。 例えば、派生クラスのオブジェクト D に対するポインターまたは参照を、D の基底クラスに対するポインターまたは参照を予期している関数に渡すことができます。 これを実行するために明示的キャストを使用する必要はありません。標準型変換が実行されます。 派生クラスに対するポインターを、明らかにアクセス可能な基底クラスを指すように、 暗黙的に変換することができます。 また派生クラスに対する参照を、基底クラスに対する参照に暗黙的に変換することもできます。
次の例では、派生クラスを指すポインターを基底クラスを指すポインターに変換する、標準型変換を示します。
#include <iostream> using namespace std; class Base { public: char* name; void display() { cout << name << endl; } }; class Derived: public Base { public: char* name; void display() { cout << name << ", " << Base::name << endl; } }; int main() { Derived d; d.name = "Derived Class"; d.Base::name = "Base Class"; Derived* dptr = &d; // standard conversion from Derived* to Base* Base* bptr = dptr; // call Base::display() bptr->display(); }
次に、上記の例の出力を示します。
Base Class
ステートメント Base* bptr = dptr は、Derived 型のポインターを Base 型のポインターに変換します。
この逆は認められていません。 基底クラスのオブジェクトへのポインターや参照を、 派生クラスへのポインターや参照に暗黙的に変換することはできません。 例えば、クラス Base および Class が上記の例のように定義されている場合、 コンパイラーは、次のコードを許可しません。
int main() { Base b; b.name = "Base class"; Derived* dptr = &b; }
コンパイラーは、ステートメントが暗黙的に Base 型のポインターを Derived 型のポインターに変換するので、 ステートメント Derived* dptr = &b を許可しません。
派生クラスのメンバーと基底クラスのメンバーが同じ名前を持っている場合、 基底クラス・メンバーは、派生クラスの中で隠されます。 派生クラスのメンバーが基底クラスと同じ名前を持っている場合、 基底クラス名は、派生クラスの中で隠されます。
関連参照