★privateメンバ関数★


本編ではあまり触れなかった、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;
}

<実行結果>

□▲□▲□□□▲□□
続行するには何かキーを押してください・・・

とりあえず、予定していたプログラムは完成しました。

しかし、ここからが本題です。


privateメンバ関数


注目してほしいのは「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メンバ関数としておきましょう。


ブラウザの戻るボタンで戻ってください。