Click here to Skip to main content
15,889,116 members
Articles / Desktop Programming / MFC
Article

Object properties for C++

Rate me:
Please Sign up or sign in to vote.
4.21/5 (21 votes)
19 May 20052 min read 94.9K   675   30   22
A small library that gives C++ objects the ability to have properties.

Introduction

The purpose of this library is to provide object properties. Instead of coding setter and getter methods, it is better to use properties because it is a more intuitive interface. Unfortunately, C++ does not offer native properties, but they can be emulated using templates and operator overloading, with a small memory overhead.

Installation

In order to use properties, you have to do include the file "property.hpp" in your project, then use the following fragment in your code:

#include "property.hpp"
using namespace cpp::properties;

The library is documented using Doxygen.

Declaring properties

The main class of this library is the class 'property'. It can be used to declare a property member. For example:

class MyClass {
public:
    property<MyClass, int> data;

    MyClass() : data(this, &MyClass::data_changed, 5) {
    }

protected:
    virtual void data_changed() {
    }
};

In the above example, a property 'data' is declared. The property class has two main parameters: the type of owner class (needed in order to make a typesafe callback interface) and the type of the property value.

The property's callback (and optional initial value) must be declared at construction time. It can not be changed afterwards. Callback parameters must not be null, otherwise your application will crash.

Using properties

Usage of properties is like data members. For example:

MyClass obj;
obj.data = 5;
int i = obj.data + 1;
cout << obj.data() << endl;

Advanced options

The default property declaration declares a property that has a read-write value stored inside the property. The type of access (read-write, read-only, write-only) and the type of storage (variable or interface) can be changed by supplying different template parameters.

Interface properties are properties that don't store the value, but they call the owner object for getting and setting the value of the property.

For example, a read-write interface property must be declared like this:

class MyClass {
public:
    property<MyClass, int, read_write, interface> data;

    MyClass() :
        m_data(0),
        data(this, &MyClass::data_get, &MyClass::data_set) {
    }

private:
    int m_data;

    const int &data_get() const {
        return m_data;
    }

    void data_set(const int &value) {
        m_data = value;
    }
};

Usage of interface properties is exactly the same as variable properties. You can do different combinations of read_write, read_only, write_only and variable, interface to provide your own taste of a property.

License

As the included readme.txt explains, it's freeware, i.e. you can do whatever you like with it, except claim it for yours (of course!).

Notes

I have modified the library so that the declaration of different flavors of properties has become simpler. It works under MS VC++ 6.0 and DevCpp 4.9.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
Greece Greece
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 2 Pin
ColdShine24-Nov-08 10:36
ColdShine24-Nov-08 10:36 
GeneralSize increase Pin
Michel Helms22-Nov-06 0:52
Michel Helms22-Nov-06 0:52 
GeneralMSVC versions Pin
Ernesto Savoretti7-Jun-06 15:31
Ernesto Savoretti7-Jun-06 15:31 
GeneralNice, but... Pin
Yevhen Fedin26-May-05 23:11
Yevhen Fedin26-May-05 23:11 
Generalimprovement! Pin
Achilleas Margaritis20-May-05 2:19
Achilleas Margaritis20-May-05 2:19 
GeneralRe: improvement! Pin
ChauJohnthan20-May-05 8:05
ChauJohnthan20-May-05 8:05 
GeneralRe: improvement! Pin
Achilleas Margaritis20-May-05 8:41
Achilleas Margaritis20-May-05 8:41 
GeneralMS specific solution Pin
cmk20-May-05 0:25
cmk20-May-05 0:25 
GeneralNot bad Pin
pshomov19-May-05 13:26
pshomov19-May-05 13:26 
GeneralRe: Not bad Pin
Achilleas Margaritis19-May-05 23:00
Achilleas Margaritis19-May-05 23:00 
GeneralRe: Not bad Pin
pshomov20-May-05 6:29
pshomov20-May-05 6:29 
Hello,

Let me see ..

Achilleas Margaritis wrote:
I personally believe that this line of solutions will not help as much as you probably hope it will. The trouble is that it requires (even) more typing then just writing the accessor methods and declaring the private member variable to persist the property.



I don't think so, for the following reasons:





in 99% of cases properties will be of read-write 'variable' type, so the actual code to write is property[class, type] name;
and name(this, &class::name_changed)
. The actual function to call when the property is changed it can be an already existing function. For example, in a GUI toolkit, most properties will be tied either to method 'redraw/update' or 'resizeFromContent'.

Using properties has the advantage of a non-bloated API. The user of the library only knows the property name. There is no need to remember naming conventions like 'get' or 'is' or 'has'.

The header file becomes less bloated.

It becomes easier to maintain documentation, as there exists one piece of documentation of the property. With methods, one needs to put the same information in the getter and setter method, or put the information in one of them and a link in the other.

Documentation becomes easier to read. The docs are not bloated with tens of little functions that do nothing more than setting and getting data.

It is easier to prototype a class, because the class can start with plain data members, and then data members can later be replaced with properties, without breaking the code.

Intellisense works better and faster since a class has less members.

A reflection library can be made that registers the properties in a class object.


These are all valid reasons. I still do not think that it will be good enough though. Again, I think the whole approach is doomed. I believe what is necessary is an extension to the language, something "native". Nothing wrong with your concrete library.

Achilleas Margaritis wrote:
class *property* is totally unnecessary.



Again, I disagree. Having the word 'property' on the source code makes the thing easier on the eye, especially after you come back to the code. For example:


class Foo {public: property[Foo, int] data1; property[Foo, float] data2; property[Foo, double] data3;};


class Foo {public: read_write[Foo, int] data1; read_write[Foo, float] data2; read_write[Foo, double] data3;};



It's clear that using 'property' has the advantage of showing immediately what the member is about. The term 'read_write' is not so obvious.


I have to agree property<foo, int=""> looks nice. How about declaring something that is not variable, or a variable which is not read_write ? It did not look that nice, did it ? I think you are persuaded that 99% of the users will be using the variable property and are not even considering what will happen when (not "if") you need a setter/getter type of property.

By saying the property is unnecessary I meant that the property class did not add or change anything on top of the policy class. That is why I do not see why you need it. And that is why I offered what I offered (the typedefs).
True

Achilleas Margaritis wrote:
That is a design decision: you can't construct the wrong property.

What do you mean *I cannot* ? If I *should not*, then you should not be offering it.


Achilleas Margaritis wrote:
Furthermore, the wrong constructor thing will not go away if the policy classes are used directly.

As far as I remember the policy classes did have only the correct constructors.

At this point I realized that you have totaly redisigned the internals of the library and basically there is no point discussing it any further. At least not what it was.

If you are interested about reasoning of the suggestions I made feel free to peek at the following books:

Exceptional C++, item 24: Uses and abuses of Inheritance
Effective C++, Item 40: Model "has-a" or "is-implemented-in-terms-of" through layering.
Effective C++, Item 44: Say what you mean; understand what you're saying.
Effective C++, Item 27: Explicitly disallow use of implicitly generated member functions you don't want


Regards,

Petar
GeneralRe: Not bad Pin
Achilleas Margaritis20-May-05 8:55
Achilleas Margaritis20-May-05 8:55 
GeneralRe: Not bad Pin
pshomov20-May-05 12:55
pshomov20-May-05 12:55 
GeneralRe: Not bad Pin
Achilleas Margaritis21-May-05 3:43
Achilleas Margaritis21-May-05 3:43 
GeneralRe: Not bad Pin
pshomov22-May-05 8:05
pshomov22-May-05 8:05 
GeneralRe: Not bad Pin
Achilleas Margaritis23-May-05 6:18
Achilleas Margaritis23-May-05 6:18 
GeneralRe: Not bad Pin
Corneliu Tusnea24-May-05 13:26
Corneliu Tusnea24-May-05 13:26 
GeneralRe: Not bad Pin
barok25-May-05 20:52
barok25-May-05 20:52 
GeneralRe: Not bad Pin
Achilleas Margaritis26-May-05 2:03
Achilleas Margaritis26-May-05 2:03 
GeneralRe: Not bad Pin
Achilleas Margaritis26-May-05 1:59
Achilleas Margaritis26-May-05 1:59 
GeneralRe: Not bad Pin
Anonymous14-Jul-05 14:53
Anonymous14-Jul-05 14:53 
GeneralNice Pin
Anonymous19-May-05 5:49
Anonymous19-May-05 5:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.