抽象クラス とは、特に基底クラスとして使用するように設計されたクラスです。
抽象クラスには、少なくとも 1 つの純粋仮想関数 が含まれています。
クラス宣言の中の仮想メンバー関数の宣言で、純粋指定子 (= 0) を使用することによって、純粋仮想関数を宣言することができます。
次に抽象クラスの例を示します。
class AB { public: virtual void f() = 0; };
関数 AB::f は、純粋仮想関数です。 関数宣言に、純粋指定子と定義の両方を入れることはできません。 例えば、コンパイラーは、次の表記を許可しません。
struct A { virtual void g() { } = 0; };
抽象クラスをパラメーター型、関数からの戻り型、または明示型変換の型として使用することはできませんし、 抽象クラスのオブジェクトも宣言することはできません。 ただし、抽象クラスを指すポインター、および参照を宣言することは可能です。 次の例は、このことを示しています。
struct A { virtual void f() = 0; }; struct B : A { virtual void f() { } }; // Error: // Class A is an abstract class // A g(); // Error: // Class A is an abstract class // void h(A); A& i(A&); int main() { // Error: // Class A is an abstract class // A a; A* pa; B b; // Error: // Class A is an abstract class // static_cast<A>(b); }
クラス A は、抽象クラスです。 コンパイラーは、関数宣言 A g() または void h(A)、 オブジェクト a の宣言、そして b の型 A への静的キャストも許可しません。
仮想メンバー関数は、継承されます。 派生クラスにある各純粋仮想関数をオーバーライドしない限り、 抽象基底クラスから派生するクラスも抽象になります。
次に例を示します。
class AB { public: virtual void f() = 0; }; class D2 : public AB { void g(); }; int main() { D2 d; }
コンパイラーは、オブジェクト d の宣言を許可しません。 D2 が、AB から純粋仮想関数 f() を継承した抽象クラスだからです。 関数 D2::g() を定義すれば、コンパイラーは、 オブジェクト d の宣言を行うことができます。
非抽象クラスから抽象クラスを派生させたり、 非純粋仮想関数を純粋仮想関数でオーバーライドできることに注意してください。
抽象クラスのコンストラクターまたはデストラクターから、メンバー関数を呼び出すことができます。 ただし、コンストラクターから純粋仮想関数を呼び出した (直接または間接) 結果は、未定義です。 次の例は、このことを示しています。
struct A { A() { direct(); indirect(); } virtual void direct() = 0; virtual void indirect() { direct(); } };
A のデフォルトのコンストラクターは、直接的、および間接的 (indirect() を介して) の両方で、純粋仮想関数 direct() を呼び出します。
コンパイラーは、純粋仮想関数の直接呼び出しには警告を出しますが、間接呼び出しには警告を出しません。
関連参照