第5章: オブジェクト指向の入口:クラスの基礎

これまでの章では、C++の基本的な文法やメモリの扱い方について学んできました。この章からは、C++の最も強力な機能の一つであるオブジェクト指向プログラミング (Object-Oriented Programming, OOP) の世界に足を踏み入れます。OOPの考え方を身につけることで、より大規模で複雑なプログラムを、現実世界の「モノ」の概念に近い形で、直感的に設計・実装できるようになります。その第一歩として、OOPの中核をなすクラスの基礎を学びましょう。

クラスとは?: データ(メンバ変数)と処理(メンバ関数)のカプセル化

他のプログラミング言語でオブジェクト指向に触れたことがあるなら、「クラスはオブジェクトの設計図」という説明を聞いたことがあるかもしれません。C++でもその考え方は同じです。クラスは、ある「モノ」が持つべき**データ(属性)と、そのデータに対する処理(操作)**を一つにまとめたものです。

  • データ(属性): クラス内に定義された変数のことで、メンバ変数 (member variables) またはデータメンバと呼びます。
  • 処理(操作): クラス内に定義された関数のことで、メンバ関数 (member functions) またはメソッドと呼びます。

このように、関連するデータと処理を一つのクラスにまとめることを、OOPの重要な概念の一つであるカプセル化 (encapsulation) と呼びます。💊

例として、「人」を表すPersonクラスを考えてみましょう。「人」は「名前」や「年齢」といったデータ(メンバ変数)を持ち、「自己紹介する」といった処理(メンバ関数)を行うことができます。

class Person { public: // メンバ変数 std::string name; int age; // メンバ関数 void introduce() { std::cout << "My name is " << name << ", and I am " << age << " years old." << std::endl; } };

class Person { ... }; という構文でクラスを定義します。クラス定義の最後にはセミコロン;が必要なので忘れないようにしましょう。現時点では、public:というキーワードは「これらのメンバは外部からアクセスできます」という意味だと考えておいてください。詳細は後ほど説明します。

インスタンスの生成: クラスからオブジェクトを作ってみる

クラスはあくまで「設計図」です。実際にプログラムで利用するためには、この設計図をもとに実体を作る必要があります。クラスから作られた実体のことをオブジェクト (object) またはインスタンス (instance) と呼び、オブジェクトを作ることをインスタンス化 (instantiation) と言います。

インスタンス化の構文は、変数の宣言とよく似ています。

instantiation.cpp

このように、クラス名 インスタンス名; という形でインスタンスを生成できます。インスタンスのメンバ変数やメンバ関数にアクセスするには、インスタンス名.メンバ名 のようにドット演算子 (.) を使います。tarohanakoは同じPersonクラスから作られたインスタンスですが、それぞれが独立したデータを持っていることがわかります。

アクセス制御: public と private による情報の隠蔽

先ほどのPersonクラスの例では、main関数からtaro.age = 30;のようにメンバ変数に直接アクセスできました。これは手軽ですが、問題を引き起こす可能性があります。例えば、年齢にマイナスの値や非現実的な値を設定できてしまうかもしれません。

Person jiro; jiro.name = "Jiro"; jiro.age = -5; // 本来ありえない値が設定できてしまう! jiro.introduce();

このような意図しない操作を防ぐために、C++にはアクセス制御の仕組みがあります。クラスのメンバは、外部からのアクセスの可否を指定できます。

  • public: クラスの外部(main関数など)から自由にアクセスできます。
  • private: そのクラスのメンバ関数からしかアクセスできません。外部からはアクセス不可です。

アクセス制御の基本は、メンバ変数はprivateにし、メンバ関数はpublicにすることです。これにより、データの不正な書き換えを防ぎ、クラスの内部実装を外部から隠蔽します。これを情報の隠蔽 (information hiding) と呼び、カプセル化の重要な目的の一つです。

privateなメンバ変数に安全にアクセスするために、publicなメンバ関数(ゲッターセッターと呼ばれる)を用意するのが一般的です。

access_control.cpp

setAge関数内で値の妥当性チェックを行っている点に注目してください。このように、クラスの利用者は内部の実装を気にすることなく、提供されたpublicなインターフェース(メンバ関数)を通じて安全にオブジェクトを操作できます。

constキーワード: getName() const のようにメンバ関数の後ろにconstを付けると、その関数がメンバ変数を変更しないことをコンパイラに約束します。このような関数をconstメンバ関数と呼びます。

コンストラクタとデストラクタ: オブジェクトが生まれてから消えるまで

オブジェクトは生成され、利用され、やがて破棄されます。このライフサイクルに合わせて特別な処理を自動的に実行するための仕組みがコンストラクタデストラクタです。

コンストラクタ (Constructor)

コンストラクタは、インスタンスが生成されるときに自動的に呼び出される特別なメンバ関数です。主な役割は、メンバ変数の初期化です。

コンストラクタには以下の特徴があります。

  • 関数名がクラス名と全く同じ。
  • 戻り値の型を指定しない(voidも付けない)。
  • 引数を取ることができ、複数定義できる(オーバーロード)。
constructor.cpp

このように、インスタンス生成時に()で初期値を渡すことで、オブジェクトを生成と同時に有効な状態にできます。set関数を別途呼び出す手間が省け、初期化忘れを防ぐことができます。

デストラクタ (Destructor)

デストラクタは、インスタンスが破棄されるとき(例えば、変数のスコープを抜けるとき)に自動的に呼び出される特別なメンバ関数です。主な役割は、オブジェクトが使用していたリソース(メモリやファイルなど)の後片付けです。

デストラクタには以下の特徴があります。

  • 関数名が ~ + クラス名。
  • 戻り値も引数も取らない。
  • 1つのクラスに1つしか定義できない。
constructor_destructor.cpp

実行結果を見ると、kenjiオブジェクトが生成されたときにコンストラクタが、create_person_scope関数のスコープを抜けるときにデストラクタが自動的に呼び出されていることがわかります。動的に確保したメモリの解放など、クリーンアップ処理はデストラクタに書くのが定石です。この考え方は、今後の章で学ぶRAII(Resource Acquisition Is Initialization)という重要な概念に繋がります。

この章のまとめ

この章では、C++におけるオブジェクト指向プログラミングの第一歩として、クラスの基本的な概念を学びました。

  • クラスは、データ(メンバ変数)と処理(メンバ関数)を一つにまとめた「設計図」です。
  • クラスから実体である**オブジェクト(インスタンス)**を生成して使用します。
  • カプセル化は、関連するデータと処理をまとめることです。
  • アクセス制御public, private)により、外部からアクセスされたくないメンバを保護します(情報の隠蔽)。
  • コンストラクタは、オブジェクト生成時に自動で呼ばれ、初期化を行います。
  • デストラクタは、オブジェクト破棄時に自動で呼ばれ、後片付けを行います。

クラスを使いこなすことで、プログラムの部品化が進み、再利用性やメンテナンス性が格段に向上します。次の章では、クラスのさらに進んだ機能について学んでいきましょう。

練習問題1: 長方形クラス

幅(width)と高さ(height)をメンバ変数として持つRectangleクラスを作成してください。

  • メンバ変数はprivateで定義してください。
  • コンストラクタで幅と高さを初期化できるようにしてください。
  • 面積を計算して返すgetArea()メソッドと、周の長さを計算して返すgetPerimeter()メソッドをpublicで実装してください。
  • main関数でRectangleクラスのインスタンスをいくつか生成し、面積と周の長さを表示するプログラムを作成してください。
practice5_1.cpp

練習問題2: 書籍クラス

タイトル(title)、著者(author)、ページ数(pages)をメンバ変数として持つBookクラスを作成してください。

  • メンバ変数はprivateで定義してください。
  • コンストラクタで、タイトル、著者、ページ数を初期化できるようにしてください。
  • 本の情報を整形してコンソールに出力するprintInfo()メソッドをpublicで実装してください。(例: Title: [タイトル], Author: [著者], Pages: [ページ数] pages
  • main関数でBookクラスのインスタンスを生成し、その情報を表示してください。
practice5_2.cpp