Click here to Skip to main content
15,888,521 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.8K   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 
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 
First of all: Congratulations on winning the Eurovision song contest. Elena is great! (I assume you are a greek or with similar origins).

Now with the other business...

Achilleas Margaritis wrote:
It goes hand-in-hand with the 'cool library, but it's all wrong, and your C++ skills suck, and mine's rock' attitude.
I did not say the library is wrong, I said it can be bettered.
I explicitly expressed my opinion about your C++ skills, I do not know why you say "...and your C++ skills suck ..." ?!?

Achilleas Margaritis wrote:
You are talking as if you've never changed any code. I knew what I wanted to achieve, I just haven't thought about how to achieve it on MSVC++ 6.0.

Change is one thing, rewrite it completely - another. Yes, I have changed and rewritten code. And that is why I always consider the criticism I get. May be they do have a point after all ...

Achilleas Margaritis wrote:
But these books refer to various C++ features necessary for following the principles they mention.

Of course they do, after all they are books about C++. But the books and especially the chapters are about features like inheritance and class constructors. Believe me, I was not trying to introduce you to these concepts. As I said the books are about using these features correctly.

Achilleas Margaritis wrote:
I see no need to read 'books' when I know 100% of what I am doing (and have done before, numerous times).

It is all up to you.

Achilleas Margaritis wrote:
I have presented one other example: using a read-write interface property. Other examples are reduntant, because all you have to do is replace 'read_write' with 'read_only/write_only' and 'variable' with 'interface'.

Yes, that is my favorite one. Let's look at it again, after all I think it is a scene to remember:

property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;

and then you have the nerve to come and say something like this ...
Achilleas Margaritis wrote:
So I see no fault at the design, especially when usage of wrong constructors ends up in a compile-time error. I also avoid your silly design with typedefs inside a struct which would make the code look ugly.

so lets look at that again

mine:
property<Foo, int>::rwi data1;

yours:
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;

By the way, rwi stands for Read-Write Interface. I agree the typedef-in-a-struct hack is not the most beautiful thing around, but it is portable and the closest I could think of to express what would be better expressed as:

Non-standard C++ follows
template<class C, class T> typedef read_write<C,T,interface<C,T> > property_rwi;

Achilleas Margaritis wrote:
So I see no fault at the design, especially when usage of wrong constructors ends up in a compile-time error.

I think what you are actually trying to express here is the so called factory pattern but the approach is incorrect. I am kind of giving up on recommending you books which are considered classics by most software developers, so I will directly offer you to google for "factory pattern".

Achilleas Margaritis wrote:
Hint: if they are as sm@rtass as you, they will certainly not. Last time I exchanged e-mails with Bjarne Stroustrup though, he did not seem to be like that.
What a minute, you exchange e-mails with Bjarne Stroustrup ?!? Why didn't you say so from the very beginning ? I am so sorry, I am taking it all back, ... or not Laugh | :laugh: .
I am sure Bjarne is a nice guy, but may be in your next e-mail exchange with him you can mention our little conflict of ideas, and ask him what he thinks. By the way, one of the books I offered you is from Herb Sutter who is currently the chair of the ISO C++ standards committee. May be this way the book will be more appealing to you Wink | ;) .

Achilleas Margaritis wrote:
How come the developer should be thinking about making them, if the compiler does not allow it? he maybe try once or twice, fail miserably, then know what is going on and never think about trying to call the wrong constructor again. It is more important that the code looks nice in the long run, for maintenance reasons.

Because before the developer tries to compile the code he will actually write it. He will check the intelliSense, look at the headers, may be even bother with the documentation. He will use one of the constructors and if he gets slapped by the compiler I am not sure you will get a second chance (we all know how compiler errors concerning templates look like - long, cryptic, etc.). Yes, I know that sometimes this is the only option, but I am saying that in this case it was totally uncalled for.
Regarding the "nice" part, the only nice part you mostly mentioned was relying on default paramters for the template so the user had absolutely idea what kind of property he had - read-only, read-write or write-only.

Achilleas Margaritis wrote:
The reason for using the proxy class and not the classes the proxy clas may possibly inherit from is purely syntactic sugar: there is only one class for programmers to know, parameterized at compile time with policy tags. It's the same tactic used with boost::smart_ptr and other high-quality libraries. I could have had 'read_write_variable_property', 'read_write_interface_property', 'read_only_variable_property' etc but it would look and feel UGLY

Actually the programmers should know about the property class and the access policy types and property storage mechanisms. Looking at your latest example reveals that:
property<MyClass, int, read_write, interface> data;

so the bad and ugly code would look like:

read_write_interface_property<MyClass, int> data;

Are still sure your point is very sound? Once again the property class brings unnecessary constructor and nothing more. Trouble, that's what it is.

Achilleas Margaritis wrote:
Not at all. Syntactic sugar is when the code is made prettier to look at, easier to write for, and consequently easier to document and maintain.

Agreed. What I was trying to say is that it changes the design. It is not only syntactic sugar. Regarding the "prettier to look at, easier to write for" part, I will have to be sm@rtass once again and say that if real sugar would be like your syntactic sugar
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;

we would have had a lot less diabetis Poke tongue | ;-P . Sorry, could not keep it.

Achilleas Margaritis wrote:
Not in every case. For example, if you have 6 different typedefs as a result of a combination of 2x3 options, it's is bad to use typedefs. It is better to use tags and selectors.

There is no such C++ constructs and I am not completely sure what you mean by "tag" and "selector", can you please clerify this for me and may be give an example in the context. I would appreciate it.

Achilleas Margaritis wrote:
He he I replied to the comment above before I read it. What you offered was not syntactic sugar, it was syntactic hell: you introduced 6 new words for the programmer to remember, plus the 'property' one. My solution has 5 words.

Ahhh, talking about syntactic hell, let me see ... this gives us one more opportunity to gaze at the beauty and conciseness of the one example I most admire:

property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;

I am sure all the keyboard producers are behind you on this one Poke tongue | ;-P . I know, I know ... being sm@rtass again.

Achilleas Margaritis wrote:
Furthermore, your identifiers where ugly: rwi, roi, rwv etc. What the heck are those? it's not clear from when looking immediately at it.
Every time you mention clarity of code I will be reminding you about your own Laugh | :laugh:

property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;

Achilleas Margaritis wrote:
Finally, there is a big problem with your solution: imagine if one more option was introduced! Let's say that there is a new property storage type called 'remote' which sends a message across the network each time the property is changed. Then your naming (rwi, roi, rwv) would be invalid, and you would have to provide 9 typedefs, where I would only have to provide one more keyword!

A few things here:
1. Apparently the naming convention I was using is not as obscure as you were pretending after all. May be you were just bitter Laugh | :laugh: .
2. No, the naming scheme would still be ok. This may come as a surprise to you but the new types would be rwr, ror, wor. Let me make this clear to you. I was not imposing my naming scheme or the exact way you want to hack around this. I was trying to offer you a direction. I was saying that using the proxy class was incorrect way to go.
3. Is writing 9 typedefs some serious problem ? If they are easy to remember, meaningful and shorter to write then I am sure they would be worth the effort. I wouldn't have minded if you would have changed the names based on your experience you so proudly wave. I guess this is not very scalable solution but these typedefs are mere shortcuts, syntactic sugar. If the user wants he can write the full thing or create his own syntactic sugar. And if you make a solution that is so complex that would be unfeasible to make all the typedefs, I am pretty sure you would have problems on your own also.
By the way this is an interesting point you are bringing up. How do you see you current implementation scale in the situation you are referring? I would have to write 3 new typedefs. You, on the other hand, would have to write 6 template specializations - 3 for Visual C++ and 3 for the others. You have to practice what you preach Big Grin | :-D .

Achilleas Margaritis wrote:
No, it was your attitude that was rude. You came on to me, saying that all I have done is wrong, and I would probably should educate myself, without giving any concrete argument on why I should do so or why my approach is wrong.
I think all you expected from the guys that looked at your class to be stunned with your exceptional C++ skills. I totally stand by all the points I made in my first post here. May be I was not clear enough when I used some terminology like IS_A and IS_IMPLEMENTED_IN_TERMS_OF so I will take this chance and apologize if that is the case. I see that you are not inclined in reading books about C++ so I have made this last effort and found a web site where the author of the book explains these things further. I hope you will consider the possibility to click on this[^] link and may be he will be more successful in getting your interest.

I spent too long time discussing this issue. I really hope you get something out of this for yourself, so at least all this typing (and trying too hard to be sm@rtass) was not a waste.

Regards,

Petar
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.