本文へスキップ
BecomeCoder

C++コース · 第11章 継承とポリモーフィズム ― 型を広げる · レッスン47

抽象クラス ― 純粋仮想関数でインターフェースを決める

ブラウザで完結

導入

「鳴く動物」を作りたいが、Animal 自体を実体化する意味はない――中身は子に必ず実装させたい。そんなときは「純粋仮想関数」を使い、そのクラスを「抽象クラス(インターフェース)」にします。

説明

virtual void speak() = 0; のように = 0 を付けると「純粋仮想関数」になります。中身を持たず、子に実装を強制します。純粋仮想関数を1つでも持つクラスは「抽象クラス」となり、それ自体はインスタンス化できません。

flowchart TB
  S["Shape(抽象クラス)<br/>virtual double area() = 0;<br/>※実体は作れない"]
  S --> C["Circle : area() を実装"]
  S --> R["Rectangle : area() を実装"]
#include <iostream>
using namespace std;

class Shape {
public:
    virtual double area() const = 0;   // 純粋仮想関数(中身なし)
    virtual ~Shape() {}                // 仮想デストラクタ(次レッスン)
};

class Circle : public Shape {
    double r;
public:
    Circle(double r) : r(r) {}
    double area() const override { return 3.14159 * r * r; }
};

class Rectangle : public Shape {
    double w, h;
public:
    Rectangle(double w, double h) : w(w), h(h) {}
    double area() const override { return w * h; }
};

int main() {
    // Shape s;   // ← エラー(抽象クラスは実体化できない)
    Shape* shapes[] = { new Circle(2), new Rectangle(3, 4) };
    for (Shape* s : shapes) {
        cout << s->area() << endl;   // 12.5664 / 12
    }
    for (Shape* s : shapes) delete s;
    return 0;
}

このように、Shape は「面積を返せる」という約束(インターフェース)だけを決め、実際の計算は各図形に任せます。新しい図形を足したいときは、Shape継承して area() を実装するだけで済みます。

まとめ

= 0 を付けた純粋仮想関数を持つクラスは抽象クラスになり、子に実装を強制します。これで「共通の約束(インターフェース)」を定義でき、拡張に強い設計ができます。C++ に interface キーワードはなく、これがその役割を果たします。

実際に動かしてみよう

下のエディタにC++を書いて「コンパイル & 実行」を押すと、ブラウザ内で本物のC++コンパイラ(clang + libc++)がその場でコンパイルして実行し、出力が表示されます。std::string・vector・クラス・テンプレート・STL などモダンC++がそのまま動きます。本文の例を書き換えて試しながら進めましょう(初回だけコンパイラの読み込みに時間がかかります。以降はキャッシュされます。この回は標準入力(cin)は使わず、値はコードに直接書きます)。

C/C++ — ブラウザ内で本物のコンパイラで実行

ブラウザ内で本物のC/C++コンパイラ(clang + libc++ / WebAssembly)を動かします。構造体・malloc/free・std::string・vector・クラス・テンプレート・STL などがそのまま実行できます(初回のみコンパイラの読み込みに時間がかかります。以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。