[C++]C#のプロパティみたいな機能

C++を使ってクラスを書いていると、メンバ変数を全てprivateにして作った変数のセッター/ゲッターを作ってという面倒くさい作業によく遭遇します。

C#のプロパティ機能があればもっと簡単に実装ができるのに、となんども思ったので、C++でC#のプロパティみたいな機能を実装してみました。

 C#のプロパティ

C#のプロパティ機能は、メンバ変数っぽい入れ物に対してセッターとゲッターを設定できて、外部からは変数にアクセスするように使えるものです。

C#
class Hoge {
    public int data {
        get {
            return _data;
        }
        set {
            if(0 < value && value < 100) {
                _data = value;
            }
        }
    }
    private int _data = 0;
};

Hoge hoge;
hoge.data = 20;    // OK data = 20
hoge.data = 100; // NG data = 20

呼び出し側ではいちいちset〇〇とかget〇〇とかを使う必要がないので、ソースの可読性/保守性も上がります。

C++でプロパティを実装

C++でも同じようにプロパティを使いたいところですが、C++にはプロパティ機能はありません。

そのため、プロパティのような機能を使うためにはデータを扱うためのラッパークラスを作って似たような機能を実装します。

C++
template<class T> class DataProxy {
public:
    DataProxy() : check([](T v){return true;}) {}
    DataProxy(const DataProxy& v) : DataProxy() {
        this->value = v.value;
        this->check = v.check;
    }
    DataProxy(const T& v) : DataProxy() {
        this->value = v;
    }
    virtual ~DataProxy() {}
    operator T() {
        return this->value;
    }
    DataProxy& operator=(const T v) {
        if(this->check(v)) {
             this->value = v;
        }
        return *this;
    }
    void setCheck(function<bool(T v)> f) {
        this->check = f;
    }
protected:
    T value;
    function<bool(T v)> check;
};

templateとoperatorを使うことでDataProxyクラスを任意の型のように振る舞わせることができるようになります。

作ったDataProxyクラスを使うには、通常のメンバ変数と同じように定義し、コンストラクタにてチェック関数を設定するだけで良いです。

C++
class Hoge {
public:
    Hoge() : data(10) {
        this->data.setCheck([](T v){return 0 < v && v < 100;});
    }
private:
    DataProxy<int> data;
};

int main() {
    Hoge hoge;
    cout << hoge.data << endl;    // 10
    hoge.data = 20;
    cout << hoge.data << endl;    // 20
    hoge.data = 100;
    cout << hoge.data << endl;    // 20

    return 0;
}

上記の例では=演算子しか使えませんが、DataProxyにoperatorを追加すれば使えるようになります。(+=や-=など)

ちなみに、checkは外部から設定/変更できてしまうため、運用規約等で変更しないようにしておかないといけません。

プロジェクトでしか使わないようであればfriendクラスに指定しておいて、protectedに変更することで外部からは変更できなくなります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です