31 декабря 2006

Properties in C++

Замечательная штука есть в современных языках программирования - properties. Берешь и пишешь: Object.Visible = True и объект отображается на экране. Хочешь проверить, отображен ли объект - пишешь If Object.Visible Then...

Все так просто! Visible - это свойство объекта "быть показанным на экране". Мы можем легко читать и изменять это свойство зная его имя.

В C++ для этого необходимо сделать accessor и mutator, то есть две функции: одна позволяющая получить значение, вторая - изменяющая значение (со всеми последствиями для объекта). Если accessor можно назвать именем свойства - bool Visible() - то как быть с mutator-ом? Назвать его Visible(bool)? Не красиво. SetVisible(bool)? Не очень понятно. Show(bool)? А как запомнить что это mutator к свойству Visible?

Более красивый вариант - прикрутить properties к C++. Загоревшись этой идеей набросал шаблон property:
template <typename T, class C>
class property
{
public:
typedef T (C::*accessor_t)() const;
typedef void (C::*mutator_t)(const T&);

property(C* object, accessor_t accessor, mutator_t mutator) :
_object(object), _accessor(accessor), _mutator(mutator) {}

operator T() const { return ((*_object).*(_accessor))(); }
property& operator=(const T& value) { ((*_object).*(_mutator))(value); return *this; }

private:
C* _object;
accessor_t _accessor;
mutator_t _mutator;
};

class range
{
public:
range(int begin, int end) : _begin(begin), _end(end) {}

int begin() const { return _begin; }
int end() const { return _end; }

public:
property<int, range> size() { return property<int, range>(this, size, setsize); }

int size() const { return _end - _begin; }
void setsize(const int& size) { _end = _begin + size; }

private:
int _begin, _end;
};

void TestProperties()
{
range r(1, 5);
cout << "range is [" << r.begin() << "," << r.end() << ") size=" << r.size() << endl;

r.size() = 2;
cout << "range is [" << r.begin() << "," << r.end() << ") size=" << r.size() << endl;
}

2 комментария:

maverick комментирует...

class CValue
{
private:
int m_value;
public:
__declspec(property(get=getValue, put=setValue)) int Value;
int getValue() { return m_value; }
void setValue(int value) { m_value = value; }
};

Вот такой простой класс позволяет обращаться к переменым через инспекторы set\get.

CValue V;
V.Value = 1; // V.setValue(1);

Raider комментирует...

это microsoft specific