Когда я впервые играл с Visual Basic (например, версия 1 или что-то), первое, что я сделал, это попытался воссоздать свойства в C ++. Возможно, раньше шаблоны были доступны для меня в то время, но теперь это будет что-то вроде:
template <class TValue, class TOwner, class TKey>
class property
{
TOwner *owner_;
public:
property(TOwner *owner)
: owner_(owner) {}
TValue value() const
{
return owner_->get_property(TKey());
}
operator TValue() const
{
return value();
}
TValue operator=(const TValue &value)
{
owner_->set_property(TKey(), value);
return value;
}
};
class my_class
{
public:
my_class()
: first_name(this), limbs(this) {}
struct limbs_k {};
struct first_name_k {};
property<std::string, my_class, first_name_k> first_name;
property<int, my_class, limbs_k> limbs;
std::string get_property(const first_name_k &);
void set_property(const first_name_k &, const std::string &value);
int get_property(const limbs_k &);
void set_property(const limbs_k &, int value);
};
Обратите внимание, что параметр "key" игнорируется в реализациях get_property
/ set_property
- он только там, чтобы эффективно действовать как часть имени функции через разрешение перегрузки.
Теперь пользователь my_class
сможет ссылаться на открытые члены first_name
и limbs
во многих ситуациях, как если бы они были необработанными полями, но они просто предоставляют альтернативный синтаксис для вызова соответствующего get_property
/ set_property
функции-члены.
Это не идеально, потому что в некоторых ситуациях вам нужно вызывать value () для свойства, чтобы получить значение, когда компилятор не может определить требуемое преобразование типа. Также вы можете получить предупреждение от передачи this
членам в конструкторе, но вы можете отключить это в этом случае.