LoginSignup
31
34

More than 5 years have passed since last update.

C++でProperty(getter/setter)

Last updated at Posted at 2013-11-04

C#のPropertyって便利だよね

C++でやるには?

とりあえず簡単に実装するなら名前を渡してメンバ変数とgetter/setterを定義するマクロ。
これは稀によく見る。
でもスマートじゃないよね。

じゃあもうTemplateしかないっしょ

書いてみた。
https://github.com/HogeTatu/cpp_module/tree/master/Property

Property基底

template <typename T>
class Property
{
public:
    Property(T& value) : _value(value) {}
    Property(const Property& ref) : _value(ref._value) {}
    virtual ~Property() {}

    Property<T>& operator = (const Property<T>& ref)
    {
        this->_value = T(ref._value);
        return *this;
    }

protected:
    T&      _value;
};

getter/setter有りなProperty

template <typename T, class Getter = SimplePropertyGetter<T>, class Setter = SimplePropertySetter<T>>
class WritableProperty : public Property<T>, private Getter, private Setter
{
public:
    WritableProperty(T& value) : Property<T>(value) {}
    WritableProperty(const WritableProperty& ref) : Property<T>(ref) {}
    virtual ~WritableProperty() {}

public:
    operator const T& () const { return this->Get(this->_value); }
    const T& operator -> () const { return this->Get(this->_value); }

    WritableProperty<T, Getter, Setter>& operator = (const T& var) { this->Set(this->_value, var); return *this; }
};

getterのみのProperty

template <typename T, class Getter = SimplePropertyGetter<T>>
class ReadOnlyProperty : public Property<T>, private Getter
{
public:
    ReadOnlyProperty(T& value) : Property<T>(value) {}
    ReadOnlyProperty(const ReadOnlyProperty& ref) : Property<T>(ref) {}
    virtual ~ReadOnlyProperty() {}

public:
    operator const T& () const { return this->Get(this->_value); }
    const T& operator -> () const { return this->Get(this->_value); }
};

デフォルトのgetterポリシー

template <typename T>
struct SimplePropertyGetter
{
    static const T& Get(const T& value) { return value; }
};

デフォルトのsetterポリシー

template <typename T>
struct SimplePropertySetter
{
    static void Set(T& value, const T& var) { value = T(var); }
};

実装内容

メンバ変数の実体をコンストラクタで渡して処理を委託する。
getter/setterの振る舞いはポリシーで切り替えられるようにした。

サンプル

こんなクラスがあったとして

class Sample
{
public:
    Sample()
        : _foo1(1)          , foo1(_foo1)
        , _bar1("bar1")     , bar1(_bar1)
        , _foo2(2)          , foo2(_foo2)
        , _bar2("bar2")     , bar2(_bar2)
    {}

    cpp_module::WritableProperty<int>           foo1;
    cpp_module::WritableProperty<std::string>   bar1;
    cpp_module::ReadOnlyProperty<int>           foo2;
    cpp_module::ReadOnlyProperty<std::string>   bar2;

private:
    int             _foo1;
    std::string     _bar1;
    int             _foo2;
    std::string     _bar2;
};

こんな感じに書ける。

Sample sample;

sample.foo1 = 10;
sample.bar1 = "sample.bar1";
output(sample.foo1);
output(sample.bar1);

//sample.foo2 = 20;                 // コンパイルエラー
//sample.bar2 = "sample.bar2";      // コンパイルエラー
output(sample.foo2);
output(sample.bar2);

ちなみにポインタ型でプロパティを定義したら a->b の形でも参照できる。

Getter、Setterの振る舞いを変えたければ、自分でポリシーを定義して

cpp_module::WritableProperty<int, CustomGetter, CustomSetter>   foo1;

みたいにしたらいい。

ちょっと考えたけど思い付かなかったから匙を投げたもの

sample.bar1.c_str()

がエラーになる。

const std::string& bar1 = sample.bar1;
bar1.c_str();

だったらOK。
a.b のオーバーロードができないからなぁ。
「こんなやり方どう?」みたいなのあったら教えて下さい。
あと何かやらかしてたら指摘して頂けると勉強になります。

31
34
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
34