Доброе утро!
В данной статье я покажу, как в C++ можно реализовать properties, подобно тому, как это сделано в C# (но с чуть меньшим сахарком).
Для начала, поймём, что же это. Properties (они же свойства) — это такие поля, обращение к которым идёт через неявный вызов геттеров и сеттеров. То есть, эдакий синтаксический сахар. Мне он не нравится как минимум по причине неявного вызова функции за синтаксисом обращения к полю, но реализовать такую функциональность на C++ захотелось попробовать.
Теперь к реализации. Идея простая. Создадим класс, от которого все эти свойства будут наследоваться. В нём добавим виртуальные методы set и get, по-умолчанию определённые такими, какими их и привычно видеть, а конструкторы, операторы присваивания и операторы работы с потоками ввода-вывода определим через них. Получается следующая милота:
#include <iostream>
template <typename T>
struct Property {
protected:
    T value;
public:
    Property() = default;
    Property(const T &value) : Property() {
        set(value);
    }
    const T & operator=(const T &value) {
        set(value);
        return this->value;
    }
    operator T() const {
        return get();
    }
    virtual void set(const T &value) {
        this->value = value;
    }
    virtual T get() const {
        return value;
    }
};
template <typename T>
std::ostream& operator<<(std::ostream &os, const Property<T> &prop) {
    os << static_cast<T>(prop);
    return os;
}
template <typename T>
std::istream& operator>>(std::istream &is, Property<T> &prop) {
    T val;
    is >> val;
    prop = val;
    return is;
}
Теперь мы можем создавать внутренние классы, сразу же объявляя поля, и перегружая методы на своё усмотрение. В геттере и сеттере получаем доступ к this->value, а в сеттере есть аргумент value, почти как в родном шарпе. Ну и добавим макросов (куда ж без них?), чтобы жилось совсем красиво:
#define PROPERTY_S(name, type, setter)               \
    struct name##name : Property<type> {             \
        name##name() = default;                      \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        void set(const type &value) setter           \
    } name
#define PROPERTY_SD(name, type, defval, setter)      \
    struct name##name : Property<type> {             \
        name##name() : Property(defval) {}           \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        void set(const type &value) setter           \
    } name
#define PROPERTY_G(name, type, getter)               \
    struct name##name : Property<type> {             \
        name##name() = default;                      \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        int get() const getter                       \
    } name
#define PROPERTY_GD(name, type, defval, getter)      \
    struct name##name : Property<type> {             \
        name##name() : Property(defval) {}           \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        int get() const getter                       \
    } name
#define PROPERTY_D(name, type, defval, setter, getter) \
    struct name##name : Property<type> {               \
        name##name() : Property(defval) {}             \
        name##name(type value) : name##name() {        \
            set(value);                                \
        }                                              \
        void set(const type &value) setter             \
        int get() const getter                         \
    } name
#define PROPERTY(name, type, setter, getter)         \
    struct name##name : Property<type> {             \
        name##name() = default;                      \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        void set(const type &value) setter           \
        int get() const getter                       \
    } name
Накидали макросов на все случаи жизни. Использование довольно просто: name — итоговое имя свойства (лучше не дублировать), type — тип хранимого значения, defval — умолчательное значение, с которым оно будет сконструировано, а getter и setter — блоки кода, тела соответствующих функций.
Добавлю компилирующийся пример, чтобы лучше видеть, как это работает:
#include <iostream>
template <typename T>
struct Property {
protected:
    T value;
public:
    Property() = default;
    Property(const T &value) : Property() {
        set(value);
    }
    const T & operator=(const T &value) {
        set(value);
        return this->value;
    }
    operator T() const {
        return get();
    }
    virtual void set(const T &value) {
        this->value = value;
    }
    virtual T get() const {
        return value;
    }
};
template <typename T>
std::ostream& operator<<(std::ostream &os, const Property<T> &prop) {
    os << static_cast<T>(prop);
    return os;
}
template <typename T>
std::istream& operator>>(std::istream &is, Property<T> &prop) {
    T val;
    is >> val;
    prop = val;
    return is;
}
#define PROPERTY_S(name, type, setter)               \
    struct name##name : Property<type> {             \
        name##name() = default;                      \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        void set(const type &value) setter           \
    } name
#define PROPERTY_SD(name, type, defval, setter)      \
    struct name##name : Property<type> {             \
        name##name() : Property(defval) {}           \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        void set(const type &value) setter           \
    } name
#define PROPERTY_G(name, type, getter)               \
    struct name##name : Property<type> {             \
        name##name() = default;                      \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        int get() const getter                       \
    } name
#define PROPERTY_GD(name, type, defval, getter)      \
    struct name##name : Property<type> {             \
        name##name() : Property(defval) {}           \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        int get() const getter                       \
    } name
#define PROPERTY_D(name, type, defval, setter, getter) \
    struct name##name : Property<type> {               \
        name##name() : Property(defval) {}             \
        name##name(type value) : name##name() {        \
            set(value);                                \
        }                                              \
        void set(const type &value) setter             \
        int get() const getter                         \
    } name
#define PROPERTY(name, type, setter, getter)         \
    struct name##name : Property<type> {             \
        name##name() = default;                      \
        name##name(type value) : name##name() {      \
            set(value);                              \
        }                                            \
        void set(const type &value) setter           \
        int get() const getter                       \
    } name
                             // \\ // \\
                             //EXAMPLE//
                             // \\ // \\
class A {
public:
    PROPERTY(val, int, { this->value = 2*value; }, { return 3*value; });
};
int main() {
    A obj;
    std::cin >> obj.val; // Enter 2 (stored 2*2=4)
    std::cerr << obj.val << std::endl; // See 3*4=12
    int a = obj.val; // Get 3*4=12
    std::cerr << a << std::endl; // See 12
    obj.val = a; // Store 2*12=24
    std::cerr << obj.val; // See 3*24=72
    return 0;
}
Прямо как в C#!
Вот мы и завезли properties в C++. Было бы интересно посмотреть на реализацию подобного механизма в какой-нибудь Java, если кто-то отважится попробовать.