20:抽象クラスと純粋仮想関数

はじめに

C++の 抽象クラス(abstract class) とは、共通のインターフェースだけを定義して、実際の処理は子クラスに任せるためのクラスです。
オブジェクト指向における「型の共通化」や「設計の基盤」に使われます。


1. 抽象クラスとは

抽象クラスは「インスタンスを生成できないクラス」です。
少なくとも1つ以上の純粋仮想関数(pure virtual function) を含みます。

関数に= 0 を付けると、その関数は純粋仮想関数になります。
(※ 戻り値が0という意味ではありません)

// 20_abstract_base.cpp
#include <iostream>
using namespace std;

class Enemy {
public:
    // 純粋仮想関数:派生クラスで必ず実装する必要がある
    virtual void attack() = 0;
};

class Slime : public Enemy {
public:
    void attack() override {
        cout << "スライムの体当たり!" << endl;
    }
};

class Goblin : public Enemy {
public:
    void attack() override {
        cout << "ゴブリンの斬撃!" << endl;
    }
};

int main() {
    // Enemy e; // エラー:抽象クラスはインスタンス生成できない

    Enemy* e1 = new Slime();
    Enemy* e2 = new Goblin();

    e1->attack();
    e2->attack();

    delete e1;
    delete e2;
}

実行結果(例)

スライムの体当たり!
ゴブリンの斬撃!

virtualを付けただけの関数なら、派生クラスで定義しなくても構いません。 ただし、純粋仮想関数(=0を付けたもの)の場合は、派生クラスで定義しないとコンパイルエラーになります。


2. 純粋仮想関数とは

純粋仮想関数は、「中身を持たない関数の宣言だけ」です。
これにより、派生クラスに「この関数を必ず定義しなければならない」というルールを課すことができます。

virtual void attack() = 0; // 実装を持たない、命令だけの関数

つまり、抽象クラスは「共通の形を定めるためのクラス」です。


3. 抽象クラスを使うメリット

メリット 内容
統一されたインターフェース 共通の基底クラスで扱えるため、コードが整理される
拡張性 新しい敵キャラを追加しても、共通のポインタで操作可能
安全性 関数の実装忘れをコンパイル時に検出できる

4. ポリモーフィズムとの関係

抽象クラスと純粋仮想関数を使うと、異なる型のオブジェクトを同じインターフェースで扱うことができます。
これは「ポリモーフィズム(多態性)」の代表的な例です。

// 20_polymorphism.cpp
#include <iostream>
#include <vector>
using namespace std;

class Enemy {
public:
    virtual void attack() = 0; // 純粋仮想関数
    virtual ~Enemy() {}        // 仮想デストラクタ
};

class Slime : public Enemy {
public:
    void attack() override { cout << "スライムの体当たり!" << endl; }
};

class Goblin : public Enemy {
public:
    void attack() override { cout << "ゴブリンの斬撃!" << endl; }
};

int main() {
    vector<Enemy*> enemies;
    enemies.push_back(new Slime());
    enemies.push_back(new Goblin());

    for (Enemy* e : enemies) {
        e->attack(); // 型ごとに異なるattack()が呼ばれる(多態性)
    }

    for (Enemy* e : enemies) delete e;
}

実行結果(例)

スライムの体当たり!
ゴブリンの斬撃!

👉 抽象クラスを基底にすることで、共通のポインタ(Enemy*)で複数の型を一括管理できます。
これはポリモーフィズム(多態性)の応用例でもあります。


✅ まとめ