09-2:ゲッター・セッター・プロパティ入門

はじめに

クラス設計では、メンバ変数への直接アクセスを避けること(カプセル化)が基本的な考え方です。変数を public にして外部から自由に操作できるようにすると、予期しない値の変更や不正な状態を引き起こす可能性があります。

そのため、変数を private にし、必要に応じてゲッター(getter)セッター(setter)を通して安全にアクセスさせる、という定番の設計手法があります。

この資料では、クラスの値を安全に扱うための3つの考え方、ゲッター(getter)セッター(setter)、そしてプロパティ(property)について学びます。

1. ゲッターとセッターとは

これらを使うことで、クラスの内部データを保護し、不正な値の代入を防ぐことができます。

基本例

// 09_2_getter_setter.cpp
#include <iostream>
using namespace std;

class Player {
private:
    int hp;
public:
    Player(int initHp) : hp(initHp) {}

    // ゲッター
    int getHp() const {
        return hp;
    }

    // セッター
    void setHp(int value) {
        if (value >= 0) hp = value; // 不正値を防ぐ
    }
};

int main() {
    Player p(100);
    cout << "初期HP: " << p.getHp() << endl;

    p.setHp(80);
    cout << "攻撃を受けた後のHP: " << p.getHp() << endl;

    p.setHp(-50); // 無効な値
    cout << "不正な値を設定後のHP: " << p.getHp() << endl;

    return 0;
}

実行結果(例)

初期HP: 100
攻撃を受けた後のHP: 80
不正な値を設定後のHP: 80
hp を直接外部から変更できないようにすることで、データの安全性を保つ。

2. ゲッター・セッターを使う目的

目的説明
安全性不正な値(例:負のHP)の代入を防ぐことができる
拡張性将来、値を変更する処理を追加しても、呼び出し側を変えずに済む
可読性getHp()setHp() の名前で、意図が明確になる

3. プロパティという考え方(C++には無い機能)

近年の言語(C# など)では、ゲッター・セッターをより自然に使えるようにしたプロパティという仕組みがよく使われています。

C++ では正式な機能としては存在しませんが、同じ考え方を理解しておくと、他の言語や将来の C++ 仕様を学ぶときに役立ちます。

C# のプロパティの例

// C#のプロパティ例
public class Player {
    private int hp;
    public int Hp {
        get { return hp; }       // 読み出し時に呼ばれる
        set {
            if (value >= 0) hp = value; // 不正値を防ぐ
        }
    }
}

void Main() {
    Player p = new Player();
    p.Hp = 100; // setterを通じて値を設定
    Console.WriteLine(p.Hp); // getterを通じて値を取得

    p.Hp = -50; // 不正な値は無視される
    Console.WriteLine(p.Hp); // 100 のまま
}
Hp に直接アクセスしているように見えますが、内部では get / set が自動的に呼ばれています。

C++ での近い書き方

C++ にはプロパティ構文はありませんが、次のように明示的に関数を書くことで同様の仕組みを表現できます。

// 09_2_property_like.cpp
#include <iostream>
using namespace std;

class Player {
private:
    int hp;
public:
    int getHp() const { return hp; }
    void setHp(int value) { hp = value; }
};
const の意味
& (参照型)について:
const int& n& は「参照型」を表します。 コピーを作らず元の値を直接参照する仕組みで、大きなデータを効率よく扱うために使います。 詳しくは 18章(拡張for文とイテレータ) で扱います。
C++ では、getter/setter を自分で定義するのが基本です。将来的に C++ にもプロパティ構文が追加される可能性はありますが、現時点では「ゲッター/セッター = 安全なアクセス方法」として理解しておくことが重要です。

コーディング演習

演習1:基本コードを動かす

09x_01_getter_setter.cpp を作成し、次のコードを入力して実行しましょう。セッターで負の値を渡したときに無視されることを確認してください。
// 09_2_getter_setter.cpp
#include <iostream>
using namespace std;

class Player {
private:
    int hp;
public:
    Player(int initHp) : hp(initHp) {}

    int getHp() const {
        return hp;
    }

    void setHp(int value) {
        if (value >= 0) hp = value;
    }
};

int main() {
    Player p(100);
    cout << "初期HP: " << p.getHp() << endl;

    p.setHp(80);
    cout << "攻撃後のHP: " << p.getHp() << endl;

    p.setHp(-50);
    cout << "不正値設定後のHP: " << p.getHp() << endl;

    return 0;
}

演習2:コードを改造する

09x_01_GetSet09_2_getter_setter.cpp をコピーして 09x_02_GetSetMod に貼り付け、次の変更を加えてみましょう:

まとめ

理解度チェック

問題09x-1

次のコードを実行したとき、3行目の出力はどれか。

Player p(100);
p.setHp(80);
p.setHp(-50);  // 不正な値
cout << p.getHp();

(セッターは if (value >= 0) hp = value; で実装されているとする)

解説を表示 正解:イ
セッターの条件 value >= 0 が false(-50 は負)なので、代入されない。直前に設定した 80 がそのまま保持される。カプセル化による不正値防御の典型例。

問題09x-2

ゲッターに const を付ける目的として正しいものはどれか。

int getHp() const { return hp; }
解説を表示 正解:ウ
メンバ関数の後ろに付く const は、その関数がオブジェクトの状態(メンバ変数)を変更しないことを宣言する。const オブジェクトからでも呼び出せるようになる。

問題09x-3

メンバ変数を private にしてゲッター・セッターを使う最大のメリットはどれか。

解説を表示 正解:ア
カプセル化の核心は「不正な状態からオブジェクトを守ること」。セッターに if (value >= 0) のようなバリデーションを加えることで、外部から誤った値を設定されてもクラスが正しい状態を維持できる。

問題09x-4

次のコードのうち、カプセル化として正しいものはどれか。

解説を表示 正解:イ
hpprivate にして、アクセスはゲッター・セッターのみに限定するのがカプセル化の正しい実装。選択肢アとエは hp が外部から直接変更できてしまう。選択肢ウはデフォルトで private だがアクセス手段がない。