名前空間
変種
操作

抽象クラス

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

インスタンス化はできないけれども基底クラスとしては使用できる抽象型を定義します。

[編集] 構文

純粋仮想関数は宣言子が以下の構文を持つ仮想関数です。

declarator virt-specifier(オプション) = 0

このシーケンス = 0純粋指定子と言い、 declarator の直後またはオプショナルな virt-specifier (override または final) の後のいずれかに現れます。

純粋指定子はメンバ関数の定義に現れることはできません。

struct Base { virtual int g(); virtual ~Base() {} };
struct A : Base {
    // OK、3つのメンバ仮想関数を宣言し、そのうち2つは純粋です。
    virtual int f() = 0, g() override = 0, h();
    // OK、デストラクタも純粋にできます。
    ~A() = 0;
    // エラー、関数定義における純粋指定子。
    virtual int b()=0 {}
};

抽象クラスは、最終オーバーライダー純粋仮想である関数を少なくともひとつ定義または継承するクラスです。

[編集] 説明

抽象クラスは汎用的な概念 (例えば形状や動物など) を表現するために使用されます。 これは具象クラス (例えば円や犬など) に対する基底クラスとして使用することができます。

抽象クラスのオブジェクトを作成することはできず (そこから派生したクラスの基底部分オブジェクトの場合は除きます)、抽象クラスの非静的データメンバを宣言することはできません。

抽象型は引数の型、関数の戻り値の型、または明示的な変換の型として使用することはできません (関数宣言の時点では引数および戻り値の型は不完全かもしれないため、これは定義および関数呼び出しの時点でチェックされることに注意してください)。

抽象クラスへのポインタおよび参照は宣言できます。

struct Abstract {
    virtual void f() = 0; // 純粋仮想関数。
}; // 「Abstract」は抽象クラスです。
 
struct Concrete : Abstract {
    void f() override {}  // 純粋でない仮想関数。
    virtual void g();     // 純粋でない仮想関数。
}; // 「Concrete」は抽象クラスではありません。
 
struct Abstract2 : Concrete {
    void g() override = 0; // 純粋仮想オーバーライダー。
}; // 「Abstract2」は抽象クラスです。
 
int main()
{
    // Abstract a; // エラー、抽象クラスです。
    Concrete b; // OK。
    Abstract& a = b; // 抽象基底を参照するのは OK。
    a.f(); // Concrete::f() への仮想ディスパッチ。
    // Abstract2 a2; // エラー、抽象クラスです (g() の最終オーバーライダーは純粋です)。
}

純粋仮想関数は定義を提供しても構いません (その純粋仮想がデストラクタの場合は提供しなければなりません)。 派生クラスのメンバ関数は修飾された関数の識別子を用いて基底クラスの純粋仮想関数を自由に呼べます。 この定義はクラス本体の外側で提供されなければなりません (関数宣言の構文は純粋指定子 = 0 と関数本体の両方は使用できません)。

抽象クラスのコンストラクタまたはデストラクタからの純粋仮想関数への仮想呼び出しを行うことは未定義動作です (それが定義を持つか否かにかかわらず)。

struct Abstract {
    virtual void f() = 0; // 純粋仮想関数。
    virtual void g() {}  // 純粋でない仮想関数。
    ~Abstract() {
        g(); // OK、 Abstract::g() を呼びます。
        // f(); // 未定義動作。
        Abstract::f(); // OK、仮想でない呼び出し。
    }
};
 
// 純粋仮想関数の定義。
void Abstract::f() { std::cout << "A::f()\n"; }
 
struct Concrete : Abstract {
    void f() override {
        Abstract::f(); // OK、純粋仮想関数を呼びます。
    }
    void g() override {}
    ~Concrete() {
        g(); // OK、 Concrete::g() を呼びます。
        f(); // OK、 Concrete::f() を呼びます。
    }
};

[編集] 関連項目