モダンC++とCでの代替手法

C++のポリモーフィズムとCの関数ポインタの表

このレッスンでは、C++の仮想関数とCの関数ポインタを使って、いろいろな種類のオブジェクトに同じ操作を呼び出します。

はじめに

動的ポリモーフィズム(dynamic polymorphism)を使うと、使う側のコードは面積の計算のような共通の操作を呼ぶだけで、具体的なオブジェクトの種類ごとにやり方を決められます。C++は仮想関数(virtual function)でこれを直接サポートし、Cでは関数ポインタでまねできます。

大切なポイント

  • C++の抽象化を学ぶ前に、Cでのやり方を理解しましょう。
  • RAIIと値のセマンティクス(value semantics)で、リソースの持ち主を表しましょう。
  • マクロや型変換より、C++の型安全な道具を優先しましょう。

CとC++のコード例

C
実行 →
main.c
#include <stdio.h>

typedef struct Shape Shape;
struct Shape {
    double value;
    double (*area)(const Shape *shape);
};

double square_area(const Shape *shape) {
    return shape->value * shape->value;
}

int main(void) {
    Shape square = {4.0, square_area};
    printf("area=%.1f\n", square.area(&square));
}
実行結果
area=16.0
C++
実行 →
main.cpp
#include <iostream>

struct Shape {
    virtual double area() const = 0;
    virtual ~Shape() = default;
};

struct Square : Shape {
    double side;

    explicit Square(double value) : side(value) {}
    double area() const override { return side * side; }
};

int main() {
    Square square(4);
    const Shape& shape = square;
    std::cout << "area=" << shape.area() << '\n';
}
実行結果
area=16

CとC++の比較

Cのstruct Shapeは関数ポインタareaを持ち、各図形がsquare_areaのような自分用の面積の関数を設定します。C++では仮想関数が同じような関数の選択の仕組みを自動で作ります。基底クラスには仮想デストラクター(virtual destructor)も用意し、基底クラスのポインタを通したオブジェクトの削除が安全に行われるようにしましょう。

C

Cは名前付けの習慣、コールバック、マクロ、文脈を持つstructを使います。

C++

C++はスコープがはっきりした型安全な抽象化を用意しており、実行時のコストはふつうかかりません。

発展問題

両方のバージョンを実行し、コードを書き換えて、それぞれの言語がもたらす安全性の違いを観察しましょう。

  • まずCで仕組みを書き、その後で対応するC++の機能を使いましょう。
  • 手作業のリソース解放をRAIIに置き換えましょう。
  • その機能がメモリの確保や仮想関数の呼び出しを生むかどうかを確認しましょう。

チャレンジで練習する

このレッスンの内容を使って実際の問題を解きましょう。各チャレンジはブラウザで動き、すぐにテストされ、AI のレビューも受けられます。

すべてのチャレンジ