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 のオーバーロードができないからなぁ。
「こんなやり方どう?」みたいなのあったら教えて下さい。
あと何かやらかしてたら指摘して頂けると勉強になります。