はじめに
プログラミングには、処理の「手順」を重視する「手続き型」と、現実世界の「モノ」に対応させて部品化する「オブジェクト指向」という考え方があります。C++は、後者のオブジェクト指向プログラミング(OOP)を強力にサポートする言語です。
OOPの中心となるのが クラス (class
) です。クラスは、データ(メンバ変数)と、そのデータを操作する関数(メンバ関数)を一つにまとめた、オブジェクトの「設計図」です。
この記事では、オブジェクト指向の考え方を体験するために、「じゃんけんゲーム」を題材として、各登場人物をオブジェクトとしてモデリングし、C++のクラスで実装する方法を解説します。
オブジェクト指向で「じゃんけんゲーム」を設計する
まず、じゃんけんゲームを「モノ」の集まりとして捉え、モデリングします。
- プレイヤー (
Player
): 手 (hand
) というデータを持ち、「手を決める (setHand
)」「手を見せる (getHand
)」という操作ができる。 - コンピューター (
Computer
): 同じく手 (hand
) というデータを持ち、「(ランダムに)手を決める」「手を見せる」という操作ができる。 - 審判 (
GameManager
): プレイヤーとコンピューターの手を受け取り、「勝敗を判定する (judge
)」「結果を表示する (showResult
)」という操作ができる。
このように、役割ごとにオブジェクトを設計することで、プログラムの見通しが良くなります。
C++での実装コード
上記の設計に基づいて、C++でじゃんけんゲームを実装します。
完成コード
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
// using namespace std; を使うと、毎回 std:: と書かなくてよくなる
using namespace std;
// --- 定数の定義 ---
const int HAND_ROCK = 0;
const int HAND_SCISSORS = 1;
const int HAND_PAPER = 2;
const int RESULT_WIN = 0;
const int RESULT_LOSE = 1;
const int RESULT_DRAW = 2;
// --- プレイヤー クラス ---
class Player {
private:
int hand; // 手(外部からは直接変更できないようにprivateにする)
public:
void setHand(); // 自分の手を決める
int getHand(); // 自分の手を教える
};
void Player::setHand() {
cout << "0:グー, 1:チョキ, 2:パー" << endl;
cout << "あなたの手を入力: ";
cin >> hand;
}
int Player::getHand() {
return hand;
}
// --- コンピューター クラス ---
class Computer {
private:
int hand;
public:
void setHand();
int getHand();
};
void Computer::setHand() {
hand = rand() % 3; // 0, 1, 2 のいずれかをランダムに設定
}
int Computer::getHand() {
cout << "コンピュータの手: " << hand << endl;
return hand;
}
// --- 審判 クラス ---
class GameManager {
private:
int result;
public:
void judge(Player p, Computer c); // 勝敗を判定する
void showResult(); // 結果を表示する
};
void GameManager::judge(Player p, Computer c) {
int playerHand = p.getHand();
int computerHand = c.getHand();
if (playerHand == computerHand) {
result = RESULT_DRAW;
} else if ((playerHand == HAND_ROCK && computerHand == HAND_SCISSORS) ||
(playerHand == HAND_SCISSORS && computerHand == HAND_PAPER) ||
(playerHand == HAND_PAPER && computerHand == HAND_ROCK)) {
result = RESULT_WIN;
} else {
result = RESULT_LOSE;
}
}
void GameManager::showResult() {
if (result == RESULT_WIN) {
cout << "あなたの勝ちです!" << endl;
} else if (result == RESULT_LOSE) {
cout << "あなたの負けです。" << endl;
} else {
cout << "引き分けです。" << endl;
}
}
// --- メイン関数 ---
int main() {
// 1. 各クラスからオブジェクト(実体)を作成
Player player1;
Computer com1;
GameManager gm;
srand(time(NULL));
// 2. 各オブジェクトのメンバ関数を呼び出して、ゲームを進行
player1.setHand();
com1.setHand();
gm.judge(player1, com1);
gm.showResult();
return 0;
}
コードの解説
クラス (class
) と構造体 (struct
) の違い
C++では、class
とstruct
は非常によく似ていますが、大きな違いが一つあります。それは、メンバのデフォルトのアクセスレベルです。
class
: デフォルトでprivate
になります(クラスの外からは見えない)。struct
: デフォルトでpublic
になります(クラスの外から自由に見える)。
オブジェクト指向では、重要なデータ(メンバ変数)を外部から勝手に変更されないように隠蔽(カプセル化)するのが基本のため、class
を使い、メンバ変数をprivate
にすることが一般的です。
private:
と public:
private:
: このキーワード以降に宣言されたメンバは、そのクラスの内部からしかアクセスできません。Player
クラスのhand
変数は、setHand
やgetHand
といった、同じクラス内のメンバ関数からのみ操作できます。public:
: このキーワード以降に宣言されたメンバは、クラスの外部から自由にアクセスできます。main
関数からplayer1.setHand()
のように呼び出せるのは、setHand
がpublic
だからです。
main
関数でのオブジェクト利用
main
関数の中では、定義したクラス(設計図)から、Player player1;
のように変数(オブジェクトの実体)を作成します。そして、player1.setHand()
のように、ドット(.
)を使って、そのオブジェクトが持つ公開されたメンバ関数を呼び出すことで、プログラムを動かしていきます。
まとめ
今回は、「じゃんけんゲーム」を例に、C++のクラスを使ったオブジェクト指向プログラミングの基本を解説しました。
- クラスは、**データ(メンバ変数)と操作(メンバ関数)**を一つにまとめた、オブジェクトの設計図。
private
でデータを保護し、public
で操作のための窓口を提供する(カプセル化)。- プログラムを、役割分担されたオブジェクト同士の連携として設計することで、大規模で複雑なシステムでも見通しが良くなり、修正や拡張が容易になる。
手続き型が「処理の流れ」を記述していくのに対し、オブジェクト指向は「モノの役割と関係性」を設計していくアプローチです。