はじめに
C++におけるクラス (class) は、オブジェクト指向プログラミング(OOP)を実現するための中心的な機能です。クラスは、関連する**データ(状態)と操作(振る舞い)**を一つのまとまりとして定義した、オブジェクトの「設計図」として機能します。
この記事では、classを理解する上で不可欠な、以下の4つの重要な概念について解説します。
classとstructの違い- オブジェクト指向とカプセル化
- 継承 (
is-a) と包含 (has-a) - クラスの前方宣言
1. class と struct の違い
C++において、classとstructの機能的な違いはごくわずかです。最も大きな違いは、デフォルトのアクセス指定子です。
class: メンバは、デフォルトでprivate(非公開)になります。struct: メンバは、デフォルトでpublic(公開)になります。
オブジェクト指向では、データを保護する「カプセル化」が重要であるため、データの隠蔽を基本とするclassの使用が一般的です。
2. オブジェクト指向とカプセル化
オブジェクト指向とは、プログラムを、関連するデータと操作をまとめた「オブジェクト」の集まりとして捉え、それらの相互作用でシステムを構築する手法です。
カプセル化は、このオブジェクト指向の基本原則の一つです。重要なデータをprivateで隠蔽し、外部からはpublicで公開された安全な手続き(メンバ関数)しか利用できなくします。これにより、各オブジェクトの独立性が高まり、プログラムの保守性や再利用性が向上します。
3. 継承 (is-a) と包含 (has-a)
クラス間の関係性を設計する際に、主に2つの基本的な関係があります。
継承 (is-a 関係)
「BはAの一種である」という関係です。 例えば、「Warrior(戦士)は Character(キャラクター)の一種である」という関係が成り立ちます。この場合、WarriorクラスはCharacterクラスを継承します。
class Character { /* ... */ };
class Warrior : public Character { /* ... */ }; // is-a
包含 (has-a 関係)
「BはAを持っている」という関係です。 例えば、「Warrior(戦士)はSword(剣)を持っている」という関係が成り立ちます。この場合、Warriorクラスは、Swordクラスのオブジェクトをメンバとして持ちます(包含します)。
class Sword { /* ... */ };
class Warrior {
private:
Sword equipped_sword; // has-a
};
これらの関係を正しく見極めることが、良いオブジェクト指向設計の鍵となります。
4. クラスの前方宣言
2つのクラスが、互いにポインタなどで参照し合うような、循環参照の関係にある場合、コンパイラに「こういう名前のクラスが後で出てきますよ」と事前に知らせる必要があります。これが前方宣言です。
サンプルコード
// 1. まずはクラスBを前方宣言
class B;
// 2. クラスAは、Bへのポインタを持てる
class A {
private:
B* pointer_to_B;
};
// 3. クラスBは、Aへのポインタを持てる
class B {
private:
A* pointer_to_A;
};
解説: class B; という一行が前方宣言です。これにより、class A の定義の中で、まだ詳細が不明な B という型へのポインタや参照をメンバとして持つことが可能になります。
まとめ
今回は、C++のclassに関連する、より概念的な側面を解説しました。これらの設計上の考え方を理解することは、単にコードを書くだけでなく、メンテナンスしやすく、拡張性の高い、優れたソフトウェアを構築する上で不可欠です。
