はじめに
C++の継承において、「is-a
関係」という重要な概念があります。これは、「車は乗り物の一種である」というように、子クラスが親クラスの一種である、という関係性を示すものです。
この is-a
関係があるため、C++では、親クラスを指すポインタを使って、子クラスのオブジェクトを指し示すことができます。これにより、親クラスの共通のインターフェースを通じて、子クラスのオブジェクトを統一的に扱うことが可能になります。
この記事では、基本クラスへのポインタが、基本クラスと派生クラスの両方のオブジェクトを指し示す様子を、RPGのキャラクターを例に解説します。
ポインタでオブジェクトを統一的に扱うサンプルコード
このコードは、Character
(キャラクター)という親クラスと、それを継承した Player
(プレイヤー)という子クラスを定義します。そして、Character
クラスへのポインタの配列 party
を使い、そこにCharacter
オブジェクトと Player
オブジェクトの両方を格納し、統一的に扱います。
完成コード
#include <iostream>
#include <string>
using namespace std;
// --- 親クラス(基本クラス) ---
class Character {
protected:
string name;
int hp;
public:
Character(string n, int h) : name(n), hp(h) {}
void showStatus() {
cout << "名前: " << name << ", HP: " << hp << endl;
}
};
// --- 子クラス(派生クラス) ---
class Player : public Character {
public:
int level;
Player(string n, int h, int l) : Character(n, h), level(l) {}
// 親クラスのshowStatus()をオーバーライド
void showStatus() {
cout << "名前: " << name << ", HP: " << hp << ", Lv: " << level << endl;
}
};
int main() {
// 1. 基本クラスのポインタの配列を準備
Character* party[2];
// 2. 親クラスと子クラスのオブジェクトを作成
Character boss("スライム", 200);
Player hero("勇者", 150, 10);
// 3. 配列にそれぞれのオブジェクトのアドレスを代入
// 親クラスへのポインタに、親クラスのアドレスを代入
party[0] = &boss;
// 親クラスへのポインタに、子クラスのアドレスを代入
party[1] = &hero;
// 4. ループで全てのオブジェクトを統一的に扱う
for(int i = 0; i < 2; i++) {
party[i]->showStatus();
}
return 0;
}
実行結果
名前: スライム, HP: 200
名前: 勇者, HP: 150, Lv: 10
コードの解説
pCars[0] = &car1;
と pCars[1] = &rccar1;
ご提示のコードのこの部分が、親クラスへのポインタに、親クラスと子クラス両方のアドレスを代入している核心部分です。
サンプルコードでは、Character* party[2];
という「Character
型を指すポインタの配列」に、Character
オブジェクトのアドレス (&boss
) と、Player
オブジェクトのアドレス (&hero
) の両方を代入しています。
これは、Player
が Character
を継承しているため、「Player
は Character
の一種である」という is-a
関係が成り立つからです。
for(int i = 0; i < 2; i++) { party[i]->showStatus(); }
このループが、このテクニックの真価を示しています。
party
配列には、Character
とPlayer
という異なる種類のオブジェクトが混在しています。- しかし、どちらも親クラスである
Character
の機能(showStatus()
)を共有しているため、party[i]->showStatus()
という同じコードで、それぞれのオブジェクトに合わせた正しいshowStatus()
関数が呼び出されています。
これにより、オブジェクトの種類を意識することなく、複数の異なるオブジェクトを統一的に扱えるようになります。
まとめ
今回は、基本クラスへのポインタが、派生クラスのオブジェクトも指し示せるという、オブジェクト指向の重要な性質を解説しました。
基本クラスへのポインタ
には、基本クラスのオブジェクト
と派生クラスのオブジェクト
の両方のアドレスを代入できる。- これにより、複数のオブジェクトを一つのポインタの配列などで管理し、統一的なインターフェースで操作できる。
この仕組みは、オブジェクト指向における「多態性(ポリモーフィズム)」の基礎であり、柔軟で拡張性の高いプログラムを構築する上で不可欠なテクニックです。