Introduction
C++ does not have real object properties like C# or VB. It is possible to add properties to C++ objects by using the preprocessor that works in the exact same way as in C#, i.e., without execution and memory overhead.
Properties have the advantage of simplifying an object's interface. With properties, there is no need to remember the prefix of a 'getter' function: is it 'get', 'is' or 'has'? Properties behave like simple data members, but when they are assigned, they invoke the owner object code.
The code
The following two macros do the job:
#include "stddef.h"
#define CLASS(NAME)\
typedef NAME ClassType;
#define PROPERTY(TYPE, NAME)\
private:\
class NAME##_class\
{\
public:\
operator TYPE () const\
{\
return get_owner_object_const()->get_##NAME();\
}\
TYPE operator = (TYPE val)\
{\
get_owner_object()->set_##NAME(val);\
return val;\
}\
private:\
ClassType *get_owner_object() const\
{\
ClassType *owner_object =
(ClassType *)((char *)this - offsetof(ClassType, NAME));\
return owner_object;\
}\
const ClassType *get_owner_object_const() const\
{\
return get_owner_object();\
}\
};\
friend class NAME##_class;\
public:\
NAME##_class NAME;
Using properties
Using properties is fairly straightforward:
- include the macro
CLASS
, passing the class name, in the public portion of your class.
- declare your properties with the macro
PROPERTY(TYPE, NAME)
. The 'type
' is the interface type, not the internal type of the property.
- place two private functions in your code that start with
get_
and set_
, suffixed with the property's name.
Example
#include "iostream"
using namespace std;
class Foo
{
public:
Foo() : m_data(0)
{
}
CLASS(Foo);
PROPERTY(int, data);
private:
int m_data;
int get_data() const
{
return m_data;
}
void set_data(int val)
{
m_data = val;
}
};
int main(int argc, char* argv[])
{
Foo foo1;
foo1.data = 5;
int i = foo1.data;
cout << i;
return 0;
}
How it works
The macro PROPERTY
is a proxy class that diverts set/get requests to the owner object's set method. The address of the owner object is calculated by the offsetof
macro.
Notes
There is no run-time cost for this solution, except for four bytes added for each member: the C++ standard dictates that empty members should have a physical representation, in order to have pointers to them. A good compiler will eliminate the proxy calls and invoke the set and get of the owner object directly.
The code above could be extended with providing read only and write only properties, as well as indexed properties.
This article is provided as an example only. Your needs may vary.