Last week I posed about making properties in C++. That code sample had some issues that I fine tuned with the code sample in this post. Here is the new class(s).
template <typename ObjectType, typename ValueType, ValueType (ObjectType::*getter)(void), void (ObjectType::*setter)(ValueType)>
class Property {
private:
ObjectType* FObject;
public:
Property() {
FObject = NULL;
}
void SetInstance(ObjectType* Value) {
FObject = Value;
}
// To set the value using the set method.
ValueType operator =(const ValueType& Value) {
assert(FObject != NULL);
(FObject->*setter)(Value);
return Value;
}
// The Property class is treated as the internal type.
operator ValueType() {
assert(FObject != NULL);
return (FObject->*getter)();
}
};
template <typename ObjectType, typename ValueType, ValueType (ObjectType::*getter)(void)>
class ReadProperty {
private:
ObjectType* FObject;
public:
ReadProperty() {
FObject = NULL;
}
void SetInstance(ObjectType* Value) {
FObject = Value;
}
// The Property class is treated as the internal type.
operator ValueType() {
assert(FObject != NULL);
return (FObject->*getter)();
}
};
template <typename ObjectType, typename ValueType, void (ObjectType::*setter)(ValueType)>
class WriteProperty {
private:
ObjectType* FObject;
public:
WriteProperty() {
FObject = NULL;
}
void SetInstance(ObjectType* Value) {
FObject = Value;
}
// To set the value using the set method.
ValueType operator =(const ValueType& Value) {
assert(FObject != NULL);
(FObject->*setter)(Value);
return Value;
}
};
template <typename ObjectType, typename ValueType, ValueType (ObjectType::getter)(void), void (ObjectType::setter)(ValueType)>
class StaticProperty {
private:
public:
StaticProperty() {
}
// To set the value using the set method.
ValueType operator =(const ValueType& Value) {
(*setter)(Value);
return Value;
}
// The Property class is treated as the internal type which is the getter.
operator ValueType() {
return (*getter)();
}
};
template <typename ObjectType, typename ValueType, ValueType (ObjectType::getter)(void)>
class StaticReadProperty {
private:
public:
StaticReadProperty() {
}
// The Property class is treated as the internal type which is the getter.
operator ValueType() {
return (*getter)();
}
};
template <typename ObjectType, typename ValueType, void (ObjectType::setter)(ValueType)>
class StaticWriteProperty {
private:
public:
StaticWriteProperty() {
}
// To set the value using the set method.
ValueType operator =(const ValueType& Value) {
(*setter)(Value);
return Value;
}
};
As you can see there are several classes. I moved the read/write/readwrite enum from being a field of the property class to being a class. I also added static versions. Oh, why would one want a static property? Well, here are a couple examples of using these:
class Environment {
public:
Environment() {
PropertyTest.SetInstance(this);
}
// Property
private:
std::string FPropertyTest;
public:
void SetPropertyTest(std::string Value) { FPropertyTest = Value; }
std::string GetPropertyTest() { return FPropertyTest; }
Property<Environment, std::string, &Environment::GetPropertyTest, &Environment::SetPropertyTest> PropertyTest;
// Static Property
private:
static std::string FTest;
public:
static void SetTest(std::string Value) { FTest = Value; }
static std::string GetTest() { return FTest; }
static StaticProperty<Environment, std::string, &Environment::GetTest, &Environment::SetTest> Test;
};
StaticProperty<Environment, std::string, &Environment::GetTest, &Environment::SetTest> Environment::Test;
std::string Environment::FTest = "foo";
There are a few limitations still. For example, the dot (.) operator cannot be overridden. So doing:
printf("%s\n", Environment::Test.data());
isn't going to work. The arrow (->) operator can be overridden, so this behavior could be supported that way if one was so inclined. Seems a little odd. I could go either way.
No comments:
Post a Comment