抽象クラス (C++)

抽象クラスは一般的な概念を表現したもので、このクラスからより具体的なクラスを派生するために使用できます。 抽象クラス型のオブジェクトを作成できません。 しかし、抽象クラス型へのポインターと参照を使用できます。

抽象クラスを作成するには、少なくとも 1 つの純粋仮想メンバー関数を宣言します。 これは、純粋な指定子 (= 0) の構文を使用して宣言される仮想関数です。 抽象クラスから派生したクラスは純粋仮想関数を実装する必要があります。つまり派生クラスも抽象クラスです。

仮想関数」に示されている例を考えます。 Account クラスの目的は一般的な機能を提供することですが、Account 型のオブジェクトは一般的すぎて役に立ちません。 したがって、Account は抽象クラスに適した候補です。

// deriv_AbstractClasses.cpp
// compile with: /LD
class Account {
public:
   Account( double d );   // Constructor.
   virtual double GetBalance();   // Obtain balance.
   virtual void PrintBalance() = 0;   // Pure virtual function.
private:
    double _balance;
};

この宣言と前の宣言の唯一の違いは、PrintBalance が純粋指定子 (= 0) で宣言されていることです。

抽象クラスに関する制約

抽象クラスは以下の項目では使用できません。

  • 変数またはメンバー データ

  • 引数の型

  • 関数の戻り値の型

  • 明示的な変換の型

抽象クラスのコンストラクターが純粋仮想関数を直接または間接的に呼び出すと、結果が未定義になります。 ただし、抽象クラスのコンストラクターとデストラクターは、他のメンバー関数を呼び出すことができます。

純粋仮想関数を定義する

抽象クラスの純粋仮想関数は、定義することもできますし、実装もあります。 次のように、完全修飾構文を使用する場合に限り、この種の関数を呼び出ことができます。

abstract-class-name::function-name()

純粋仮想関数を定義することは、基底クラスに純粋仮想デストラクターが含まれるクラス階層を設計する場合に役立ちます。 その理由は、オブジェクトの破棄中には基底クラスのデストラクターが必ず呼び出されるからです。 次の例を考えてみましょう。

// deriv_RestrictionsOnUsingAbstractClasses.cpp
// Declare an abstract base class with a pure virtual destructor.
// It's the simplest possible abstract class.
class base
{
public:
    base() {}
    // To define the virtual destructor outside the class:
    virtual ~base() = 0;
    // Microsoft-specific extension to define it inline:
//  virtual ~base() = 0 {};
};

base::~base() {} // required if not using Microsoft extension

class derived : public base
{
public:
    derived() {}
    ~derived() {}
};

int main()
{
    derived aDerived; // destructor called when it goes out of scope
}

この例は、Microsoft コンパイラ拡張機能で、純粋仮想 ~base() にインライン定義を追加する方法を示しています。 base::~base() {} を使用してクラス外で定義することもできます。

オブジェクト aDerived がスコープ外の場合、クラス derived のデストラクターが呼び出されます。 コンパイラは、デストラクター derived の後にクラス base のデストラクターを暗黙的に呼び出すコードを生成します。 純粋仮想関数 ~base の空の実装は、その関数に対して少なくとも実装が存在することを保証します。 存在しないと、リンカーは暗黙的な呼び出しに対する未解決の外部シンボル エラーを生成します。

Note

前の例では、純粋仮想関数 base::~base は、derived::~derived から暗黙的に呼び出されます。 完全修飾メンバー関数名を使用して、純粋仮想関数を明示的に呼び出すこともできます。 この種の関数には実装が必要です。実装がない場合は、呼び出しを行うとリンク時にエラーが発生します。

関連項目

継承