C++の 抽象クラス(abstract class)
とは、共通のインターフェースだけを定義して、実際の処理は子クラスに任せるためのクラスです。
オブジェクト指向における「型の共通化」や「設計の基盤」に使われます。
抽象クラスは「インスタンスを生成できないクラス」です。
少なくとも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を付けたもの)の場合は、派生クラスで定義しないとコンパイルエラーになります。
純粋仮想関数は、「中身を持たない関数の宣言だけ」です。
これにより、派生クラスに「この関数を必ず定義しなければならない」というルールを課すことができます。
virtual void attack() = 0; // 実装を持たない、命令だけの関数つまり、抽象クラスは「共通の形を定めるためのクラス」です。
| メリット | 内容 |
|---|---|
| 統一されたインターフェース | 共通の基底クラスで扱えるため、コードが整理される |
| 拡張性 | 新しい敵キャラを追加しても、共通のポインタで操作可能 |
| 安全性 | 関数の実装忘れをコンパイル時に検出できる |
抽象クラスと純粋仮想関数を使うと、異なる型のオブジェクトを同じインターフェースで扱うことができます。
これは「ポリモーフィズム(多態性)」の代表的な例です。
// 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*)で複数の型を一括管理できます。
これはポリモーフィズム(多態性)の応用例でもあります。
virtual void 関数() = 0;
で純粋仮想関数を定義できる。