Introduction
C++ lacks a rich reflection mechanism - so you have to write your own or use a library like the one that boost provides. I've been toying with this idea for quite a while and I think that I have an idea of how you would do this. The very first thing you would aim for is brevity - here's my idea of what a reflection class could look like. Imagine you have a class 'AClass
' and you want to reflect it.
Sample Classes and Reflection Stub
class AClass
{
public:
int aValue;
int anotherValue;
std::string thirdValue;
};
class AClass2
{
public:
std::string testing;
std::string testing2;
};
template<typename T>
class ClassDescriptor
{
};
template<>
class ClassDescriptor<AClass>
{
public:
template<typename TCallback>
void for_each_property(const TCallback& callback)
{
callback("aValue", &AClass::aValue);
callback("anotherValue", &AClass::anotherValue);
callback("thirdValue", &AClass::thirdValue);
}
};
template<>
class ClassDescriptor<AClass2>
{
public:
template<typename TCallback>
void for_each_property(const TCallback& callback)
{
callback("testing", &AClass2::testing);
callback("testing2", &AClass2::testing2);
}
};
template<typename TClass>
ClassDescriptor<TClass> GetClassDescriptor(TClass& t)
{
return ClassDescriptor<TClass>();
}
Sample Algorithm
A template specialisation allows you to represent any class type that you're interested in and you can capture the offset for each of the properties of that represented class. Then, all you need to do is represent the algorithm:
template<typename TClass>
class SamplePropertyAlgorithm
{
TClass& m_t;
public:
SamplePropertyAlgorithm(TClass& t):m_t(t)
{
}
template<typename TPropertyType>
void operator()(const char* szProperty,
TPropertyType TClass::*pPropertyOffset) const
{
std::cout << szProperty << ": " << m_t.*pPropertyOffset << std::endl;
std::cout << "enter new value:" << m_t.*pPropertyOffset;
std::cout << szProperty << ": " << m_t.*pPropertyOffset << std::endl;
}
};
template<typename T>
void RunAlgorithm(T& t)
{
GetClassDescriptor(t).for_each_property(SamplePropertyAlgorithm<T>(t));
}
Wow! That was a mouthful, but you only have to write it once, for each property, and you've captured not only the name but the type and value of each property.
Sample Usage
For illustration, here is the usage:
int main(int argc, const char * argv[])
{
AClass c1;
c1.aValue = 1;
c1.anotherValue = 2;
c1.thirdValue = "this is a test";
AClass2 c2;
c2.testing = "ABC";
c2.testing2 = "DEF";
RunAlgorithm(c1);
RunAlgorithm(c2);
return 0;
}
Sample Interaction
And here is a sample interaction with the program:
aValue: 1
enter new value:2
aValue: 2
anotherValue: 2
enter new value:3
anotherValue: 3
thirdValue: this is a test
enter new value:test
thirdValue: test
testing: ABC
enter new value:EEE
testing: EEE
testing2: DEF
enter new value:FF
testing2: FF
There you have it. I'm sure you can make this briefer using the preprocessor, and abstract it further allowing more kinds of properties - such as getter and setter methods. I'll think it over. Thanks for reading.
This article was originally posted at: