Pull to refresh

Property в С++ на С++ (без применения препроцессора)

Reading time2 min
Views2.1K
Навеяно статьей Property в C++

За пять минут размышлений, как обойтись без директив препроцессора, появилось нечто…

Может ли это «нечто» быть полезным, осмысливать лень. Есть масса недостатков, нет доступа по имени, зато без макросов )

up: геттер-сеттер — сделаны методами класса

#include <string>
#include <map>
#include <iostream>

using namespace std;

template<class B,class T> class DefineProperty
{
    T value;
    B *that;

    typedef void (B::*SetterPtr)(const T&); 
    typedef T (B::*GetterPtr)(const T&) const; 

    void (B::*setter)( const T &val );
    T (B::*getter)( const T &val ) const;

public:
    DefineProperty()
    {
        setter = NULL;
        getter = NULL;
        that   = NULL; 
    }

    DefineProperty(B *self, GetterPtr get, SetterPtr set)
    {
        that   = self;
        setter = set;
        getter = get;
    }

    DefineProperty(B *self, SetterPtr set, GetterPtr get)
    {
        that   = self;
        setter = set;
        getter = get;
    }

    DefineProperty(B *self, GetterPtr get)
    {
        that   = self;
        setter = NULL;
        getter = get;
    }

    DefineProperty(B *self, SetterPtr set)
    {
        that   = self;
        setter = set;
        getter = NULL;
    }

    void operator = ( const T &val )
    {
        set( val );
    }

    void set( const T &val )
    {
        value = val;

        if( setter )
            (that->*setter)( val );
    }

    operator T () const
    { 
        return get();
    }

    T get() const
    {
        if( getter )
            return (that->*getter)(value);

        return value; 
    }

    T field_get() const
    {
        return value; 
    }

    void field_set( const T &val )
    {
        value = val; 
    }
};

template<class T,class B>
std::ostream& operator<<(std::ostream &out, const DefineProperty<T,B> &val)
{
    out << (val.get());
    return out;
}

class ClassWithProps
{
public:
    DefineProperty<ClassWithProps,int>     Integer;
    DefineProperty<ClassWithProps,int>     PlainInteger;
    DefineProperty<ClassWithProps,int>     FakedInteger;
    DefineProperty<ClassWithProps,string>  String;

    // Disable warning 4355 - use this pointer in ctor
    // There is no violation in this particular case
    #pragma warning( push )
    #pragma warning( disable: 4355 )

    ClassWithProps()
    // Getter-Setter declaration
     : Integer(this, &ClassWithProps::IntegerSetter),
       FakedInteger(this, &ClassWithProps::IntegerGetter), 
       String(this, &ClassWithProps::StringGetter, &ClassWithProps::StringSetter)
    {
    }

    #pragma warning( pop )

private:
    void IntegerSetter( const int &value )
    {
        cout << "Set(" << value << ")" << endl;
        Integer.field_set(value+1);
    }

    int IntegerGetter( const int &value ) const
    {
        return value * 2;
    }

    string StringGetter( const string &value ) const
    {
        return "I love " + value;
    }

    void StringSetter( const string &value )
    {
    }
};

int main(int argc, char* argv[])
{
    ClassWithProps props;

    // not getter/setter
    props.PlainInteger = 1;
    int plain = props.PlainInteger;

    // only setter
    props.Integer = 100;
    int real = props.Integer;

    // only getter
    props.FakedInteger = 100;
    int faked = props.FakedInteger;

    // getter and setter
    props.String = "habr";
    string str = props.String;

    // allow to use ostream
    cout << "Faked integer = " << props.FakedInteger << endl;
    cout << props.String << endl;

    return 0;
}
Tags:
Hubs:
+6
Comments9

Articles