本編ではあまり触れなかった、privateメンバ関数について説明します。
まずはサンプルを作ってみます。
「すごろく」のほんの一部だけイメージして、Sugorokuクラスを作りましょう。
クラスに10個の要素を持った配列を用意し、その中に最大3つのイベントを設置します。
表示の際には、通常のマスを「□」、イベントマスを「▲」で表します。
※用意するのは、cppファイルだけで構いません。
それではクラスの宣言部分を書きましょう。
<sample program col_cpp003-01>
#include <iostream> #include <cstdlib> #include <ctime> class Sugoroku { public: Sugoroku(); //初期化 void Initialize(); //表示 void Show() const; private: const int EVENT; enum { SIZE = 10 }; int m_masu[SIZE]; }; |
関数は、コンストラクタ関数、「Initialize関数」、「Show関数」の3つを用意しました。
定数EVENTは、イベントの最大数を格納する定数として用意します。
EVENTの初期値をコンストラクタ関数の初期化リストで設定します。
<sample program col_cpp003-02>
#include <iostream>
#include <cstdlib>
#include <ctime>
class Sugoroku {
public:
Sugoroku();
//初期化
void Initialize();
//表示
void Show() const;
private:
const int EVENT;
enum { SIZE = 10 };
int m_masu[SIZE];
};
Sugoroku::Sugoroku() : EVENT(3)
{
}
|
イベントの最大数は3にしました。
続いて「Initialize関数」を追加します。
<sample program col_cpp003-03>
#include <iostream>
#include <cstdlib>
#include <ctime>
class Sugoroku {
public:
Sugoroku();
//初期化
void Initialize();
//表示
void Show() const;
private:
const int EVENT;
enum { SIZE = 10 };
int m_masu[SIZE];
};
Sugoroku::Sugoroku() : EVENT(3)
{
}
//初期化
void Sugoroku::Initialize()
{
//配列のクリア
for (int i = 0; i < SIZE; i++) {
m_masu[i] = 0;
}
//イベントの配置
for (int i = 0; i < EVENT; i++) {
m_masu[rand() % SIZE] = 1;
}
}
|
配列の全ての要素に「通常のマス(0)」を入れた後で、乱数を使って「イベントマス(1)」を格納しました。
最後に「Show関数」を追加します。
<sample program col_cpp003-04>
#include <iostream>
#include <cstdlib>
#include <ctime>
class Sugoroku {
public:
Sugoroku();
//初期化
void Initialize();
//表示
void Show() const;
private:
const int EVENT;
enum { SIZE = 10 };
int m_masu[SIZE];
};
Sugoroku::Sugoroku() : EVENT(3)
{
}
//初期化
void Sugoroku::Initialize()
{
//配列のクリア
for (int i = 0; i < SIZE; i++) {
m_masu[i] = 0;
}
//イベントの配置
for (int i = 0; i < EVENT; i++) {
m_masu[rand() % SIZE] = 1;
}
}
//表示
void Sugoroku::Show() const
{
for (int i = 0; i < SIZE; i++) {
switch (m_masu[i]) {
case 0:
std::cout << "□";
break;
case 1:
std::cout << "▲";
break;
}
}
std::cout << std::endl;
}
|
クラスはこれで完成です。
main関数を追加して、メンバ関数を呼び出してみましょう。
<sample program col_cpp003-05>
#include <iostream>
#include <cstdlib>
#include <ctime>
class Sugoroku {
public:
Sugoroku();
//初期化
void Initialize();
//表示
void Show() const;
private:
const int EVENT;
enum { SIZE = 10 };
int m_masu[SIZE];
};
int main()
{
srand((unsigned int)time(NULL));
Sugoroku sugoroku;
sugoroku.Initialize();
sugoroku.Show();
return 0;
}
Sugoroku::Sugoroku() : EVENT(3)
{
}
//初期化
void Sugoroku::Initialize()
{
//配列のクリア
for (int i = 0; i < SIZE; i++) {
m_masu[i] = 0;
}
//イベントの配置
for (int i = 0; i < EVENT; i++) {
m_masu[rand() % SIZE] = 1;
}
}
//表示
void Sugoroku::Show() const
{
for (int i = 0; i < SIZE; i++) {
switch (m_masu[i]) {
case 0:
std::cout << "□";
break;
case 1:
std::cout << "▲";
break;
}
}
std::cout << std::endl;
}
|
<実行結果>
□▲□▲□□□▲□□ 続行するには何かキーを押してください・・・
とりあえず、予定していたプログラムは完成しました。
しかし、ここからが本題です。
注目してほしいのは「Initialize関数」です。
//初期化 void Sugoroku::Initialize() { //配列のクリア for (int i = 0; i < SIZE; i++) { m_masu[i] = 0; } //イベントの配置 for (int i = 0; i < EVENT; i++) { m_masu[rand() % SIZE] = 1; } } |
この関数には「配列のクリア」と「イベントの配置」と言う2つの機能があります。
基本的に機能の異なるものは、関数に分割する事を考えます。
関数分割するために、クラスに2つのメンバ関数を新しく作ります。
class Sugoroku {
public:
Sugoroku();
//初期化
void Initialize();
//表示
void Show() const;
//配列のクリア
void ClearMasu();
//イベントの配置
void SetEvent();
private:
const int EVENT;
enum { SIZE = 10 };
int m_masu[SIZE];
};
|
この2つの関数の本体を↓のように追加します。
//配列のクリア
void Sugoroku::ClearMasu()
{
for (int i = 0; i < SIZE; i++) {
m_masu[i] = 0;
}
}
//イベントの配置
void Sugoroku::SetEvent()
{
for (int i = 0; i < EVENT; i++) {
m_masu[rand() % SIZE] = 1;
}
}
|
内容は「Initialize関数」の中身と同じですね。
最後に「Initialize関数」を書き換えます。
//初期化 void Sugoroku::Initialize() { //配列のクリア ClearMasu(); //イベントの配置 SetEvent(); } |
<実行結果>
□□□▲▲□□□▲□ 続行するには何かキーを押してください・・・
分割しても同じ動作をする事を確認してください。
もう1度、クラスの宣言を確認します。
class Sugoroku {
public:
Sugoroku();
//初期化
void Initialize();
//表示
void Show() const;
//配列のクリア
void ClearMasu();
//イベントの配置
void SetEvent();
private:
const int EVENT;
enum { SIZE = 10 };
int m_masu[SIZE];
};
|
「ClearMasu関数」「SetEvent関数」は、publicで宣言されています。
しかし、この2つの関数は、このクラスの「Initialize関数」以外から呼び出される事はありません。
つまり、publicにする「意味が無い」と言う事です。
「意味が無い」と言うよりは、他から呼び出されると「危険」でさえあります。
このような場合、↓のよう対応します。
class Sugoroku {
public:
Sugoroku();
//初期化
void Initialize();
//表示
void Show() const;
private:
const int EVENT;
enum { SIZE = 10 };
int m_masu[SIZE];
//配列のクリア
void ClearMasu();
//イベントの配置
void SetEvent();
};
|
メンバ関数の宣言を、privateに移動しました。
実行してみます。
<実行結果>
▲□□▲□▲□□□□ 続行するには何かキーを押してください・・・
特に問題無く実行出来ます。
機能が盛りだくさんの関数や行数の長い関数は、何をやっているのか分からなくなり、バグが発生しても取り除きづらくなります。
メンバ関数も機能ごとに分割し、他から呼び出されない関数はprivateメンバ関数としておきましょう。
ブラウザの戻るボタンで戻ってください。