Properties don't mean that the members are public.
It is also possible to overload the accessor, so they have the same name.
Code:
btn->Text("sth");
string var = btn->Text();
Similarly, it is possible to use types that overload operator= and conversion for the value type.
For example:
Code:
namespace properties
{
enum {
no_restrictions = 0,
no_setter = 1,
no_mutable_getter = 2,
no_getter = 4,
immutable = no_setter | no_mutable_getter
};
namespace detail
{
template <class Derived, class ValueType, bool HasSetter>
struct Setter
{
Derived& operator= (const ValueType& value)
{
static_cast<Derived&>(*this).value = value;
return static_cast<Derived&>(*this);
}
};
template <class Derived, class ValueType>
struct Setter<Derived, ValueType, false> {};
template <class Derived, class ValueType, bool HasGetter, bool HasMutableGetter>
struct Getter
{
operator ValueType& ()
{
return static_cast<Derived&>(*this).value;
}
operator const ValueType& () const
{
return static_cast<const Derived&>(*this).value;
}
};
template <class Derived, class ValueType>
struct Getter<Derived, ValueType, true, false>
{
operator const ValueType& ()
{
return static_cast<Derived&>(*this).value;
}
operator const ValueType& () const
{
return static_cast<const Derived&>(*this).value;
}
};
template <class Derived, class ValueType, bool Ignored>
struct Getter<Derived, ValueType, false, Ignored>{};
} //detail
template <class ValueType, unsigned DisabledFlag = properties::no_restrictions>
class DefaultProperty:
public detail::Setter<
DefaultProperty<ValueType, DisabledFlag>,
ValueType,
(DisabledFlag & properties::no_setter) == 0
>,
public detail::Getter<
DefaultProperty<ValueType, DisabledFlag>,
ValueType,
(DisabledFlag & properties::no_getter) == 0,
(DisabledFlag & properties::no_mutable_getter) == 0
>
{
ValueType value;
public:
explicit DefaultProperty(const ValueType& value = ValueType()): value(value) {}
using detail::Setter<
DefaultProperty<ValueType, DisabledFlag>,
ValueType,
(DisabledFlag & properties::no_setter) == 0
>::operator=;
private:
friend class detail::Setter<
DefaultProperty<ValueType, DisabledFlag>,
ValueType,
(DisabledFlag & properties::no_setter) == 0
>;
friend class detail::Getter<
DefaultProperty<ValueType, DisabledFlag>,
ValueType,
(DisabledFlag & properties::no_getter) == 0,
(DisabledFlag & properties::no_mutable_getter) == 0
>;
};
}
struct X
{
properties::DefaultProperty<int> a;
properties::DefaultProperty<int, properties::no_setter> b;
properties::DefaultProperty<int, properties::immutable> c;
};
#include <iostream>
int main()
{
X x, y;
y.a = x.a = 100;
std::cout << x.a << ' ' << y.a << '\n';
//x.b = 50;
std::cout << x.b << '\n';
//x.c = 75;
int c = x.c;
//int& d = x.c;
std::cout << c << '\n';
}
This example allows some customizability as to whether the default implementations of getters and setters are available or not (commented-out lines cause errors).
Other property types might be added that allow calling a method of the parent class.