Monday, April 20, 2015

Properties in C++

A long time ago when I was working on Borland C++ and Delphi was just a baby, we added properties as a language extension to C++. Nobody at the C++ committee liked the notion (not sure why, but Java didn't like it either), but I came up with a way of doing properties in C++ using templates. Here is the property class:

enum PropertyType {READ_ONLY, WRITE_ONLY, READ_WRITE};

template <typename Container, typename ValueType, PropertyType Type>
class Property {
private:
    Container* FObject;
    void (Container::*FSetter)(ValueType value);
    ValueType (Container::*FGetter)();
    
public:
    Property() {
        FObject = NULL;
        FSetter = NULL;
        FGetter = NULL;
    }
    
    void InitializeSetterGetter(Container* Value,
                                void (Container::*Setter)(ValueType Value),
                                ValueType (Container::*Getter)()) {
        assert(Type == READ_WRITE);
        FObject = Value;
        FSetter = Setter;
        FGetter = Getter;
    }

    void InitializeSetter(Container* Value,
                          void (Container::*Setter)(ValueType Value)) {
        assert(Type == WRITE_ONLY);
        FObject = Value;
        FSetter = Setter;
    }

    void InitializeGetter(Container* Value,
                          ValueType (Container::*Getter)()) {
        assert(Type == READ_ONLY);
        FObject = Value;
        FGetter = Getter;
    }
    
    // To set the value using the set method.
    ValueType operator =(const ValueType& Value) {
        assert(FObject != NULL);
        assert(FSetter != NULL);
        (FObject->*FSetter)(Value);
        return Value;
    }
    
    // The Property class is treated as the internal type.
    operator ValueType() {
        assert(FObject != NULL);
        assert(FGetter != NULL);
        return (FObject->*FGetter)();
    }

};

Now, to use this, call one of the Initializer* functions from within your classes constructor, provide getter and setter methods and instantiate the property as follows:

class TestProperty {
protected:
    std::string FMyProperty;
    
public:
    TestProperty() {
        MyProperty.InitializeGetter(this,
                                    &TestProperty::SetMyProperty
                                    &TestProperty::GetMyProperty);
    }

    std::string GetMyProperty() {
        return FMyProperty;
    }

    void SetMyProperty(std::string Value) {
        FMyProperty = Value
    }
    
    Property<Process, std::string, READ_WRITEMyProperty;
};

It's a bit more work than if you were to use a language that supports properties such as Delphi or C#, but it can be a very handy syntactic sugar.

No comments:

Post a Comment