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

Thanks, but who cares? I think the Eurovision contest was given too much attention.

Petar K. Shomov wrote:
I do not know why you say "...and your C++ skills suck ..." ?!?

Because it is that what you've said. Don't try to wrap it up in a few nice words.

Petar K. Shomov wrote:
Change is one thing, rewrite it completely - another.

It's not my fault that VC++ 6.0 sucks that badly when it comes to templates.

Anyway, changing a piece of code, even completely, is not a criterion of one's worth, as you implied. It's totally irrelevant.

Petar K. Shomov wrote:
But the books and especially the chapters are about features like inheritance and class constructors.

Syntactic sugar matters more than 'inheritance and constructors'.
Petar K. Shomov wrote:
It is all up to you.

Of course(doh!!!).

Petar K. Shomov wrote:
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


What I wanted to do is:

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


I did it, after having thought of a trick to get around VC++ 6.0 limitations.

And what if I wanted this?

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


Then your solution would not work.

Petar K. Shomov wrote:
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".

Bullshit, and your "teacher" style gets on my nerves! I am not trying to express the factory pattern, I am trying to use the policy pattern!

Petar K. Shomov wrote:
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 .

He was much more polite that you. Your manners are ...lamentable, to say the least.

Petar K. Shomov wrote:
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

I was offering an example of people that are real gurus and much less smarta$$ than you. If Herb Sutter is a nice guy, I am all for him.


Petar K. Shomov wrote:
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

But in order to write it, he would have to look at the documentation!!! otherwise, what he will write? so it's documentation first, not the other way around.

Oh now I got it! you have mystical powers and you can grab a library and start coding with it immediately without looking at the docs first...;)

Petar K. Shomov wrote:
(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.

Actually, in both your case and my case, the compiler error messages are very similar, and therefore similarly cryptic.

I personally have not ever had a problem with error messages though, because I simply ignore the template parameters (which are those that cause the cryptic problem), and read the rest of the text.

Petar K. Shomov wrote:
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.


...as the docs say, the default is 'read/write'. What's the most common case? it's read/write. Right, you say that the most common case that 99% of times will be used is "having no idea".

So, by your principles, all identifiers in a program should be patched with their types, eh?

Hungarian notation is ...so bad...!!! I am sure your books tell you that.

Petar K. Shomov wrote:
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;


Man, what are you saying? let me tell you that again, and maybe you will understand it.
Here are the things one should know:

1) class property
2) class read_write
3) class read_only
4) class write_only
5) class variable
6) class interface

Let's see, with your method, what the programmer should know:

1) class property
2) class property<C, T>::rwv
3) class property<C, T>::rwi
4) class property<C, T>::rov
5) class property<C, T>::roi
6) class property<C, T>::wov
7) class property<C, T>::woi

So, in your case, the programmer has to know one more thing!

Furthermore, my method is vastly cleaner than yours.

And you conventiently sidestep the fact that, if one more policy is added to the library, your method sucks badly.

Petar K. Shomov wrote:
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.

First of all, what we discuss above has nothing to do with the necessity of constructors.

Secondly, there is no such thing as an 'unneccessary constructor'. The constructors are needed, because they can not be avoided while the syntax I want to offer.

Petar K. Shomov wrote:
What I was trying to say is that it changes the design. It is not only syntactic sugar.

So what?

Petar K. Shomov wrote:
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.

"Tags used as selectors" means classes that can not be instantiated and used as strong types for doing partial or full template specialization.

Petar K. Shomov wrote:
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;


Well, let's compare the 99% case:

mine:

property<MyClass, int> data;


yours:

property<MyClass, int>::rwv data;


Which one looks better?

And I finally did what I wanted to achieve in the first place (but did not occur to me right away):

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


Which still looks much better than your offer.

Petar K. Shomov wrote:
I am sure all the keyboard producers are behind you on this one . I know, I know ... being sm@rtass again.

Since when having to type a little more is bad? are you a fan of APL?;P

Oh now I get it...your favorite competition is the obfuscated C contest! that explains all!Big Grin | :-D

Petar K. Shomov wrote:
Every time you mention clarity of code I will be reminding you about your own

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


Thanks. You saved me from typing that my solution is so much clearer:

mine:

property<MyClass, int> data;

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


yours:

property<MyClass, int>::rwv data;

property<MyClass, int>::rwi data;



Petar K. Shomov wrote:
Apparently the naming convention I was using is not as obscure as you were pretending after all. May be you were just bitter

Another "argument" of yours with no basis whatsoever. Actually, I am bitter about the level of "smarta$$ness" of humanity. If everyone's like you, then we've had it.

Petar K. Shomov wrote:
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.

Bullshit: ror, wor and every other abbreviation you might imagine is bad, bad, bad, especially when there are lots of them.

Petar K. Shomov wrote:
I was trying to offer you a direction.

You have to understand my direction first. Obviously, you did not.

Petar K. Shomov wrote:
I was saying that using the proxy class was incorrect way to go.

But you did not present a single argument about why.

Petar K. Shomov wrote:
Is writing 9 typedefs some serious problem ?

It depends on the context. Without context, it sounds innocent. But in this context, it's bad.

Petar K. Shomov wrote:
If they are easy to remember, meaningful and shorter to write then I am sure they would be worth the effort.

Let's see:

rwv
rwi
rwr
rov
roi
ror
wov
woi
wor


It's very very bad. Compare it with:

read_write
read_only
write_only
variable
interface
remote


Let's suppose we have one more type, the 'debug' storage, which actually prints a debug message each time the property is changed. Then, with your way, we have:

rwv
rwi
rwr
rwd
rov
roi
ror
rod
wov
woi
wor
wod


With my way:

read_write
read_only
write_only
variable
interface
remote
debug


I think that my way is vastly superior in readability.

Let's say now that we would like to do a compicated thing: wrap storage implementation around the debug class (so we can combine 'debug' capabilities with 'variable', 'interface' and 'remote'.

Your way:

rwv
rwi
rwr
rov
roi
ror
wov
woi
wor
rwvd
rwid
rwrd
rovd
roid
rord
wovd
woid
word


My way:

read_write
read_only
write_only
variable
interface
remote
debug<variable>
debug<interface>
debug<remote>


Petar K. Shomov wrote:
I would have to write 3 new typedefs. You, on the other hand, would have to write 6 template specializations

You are a cheater: how are you supposed to write the typedefs, without the implementations? so you would have too to write the new implementations.

Petar K. Shomov wrote:
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

There are ways around that. I can actually write the implementation once and share it with VC++ and others.

But you are still a cheater: the problem you mention (having to maintain too versions, because the compilers are stupid) has nothing to do with syntactic sugar.

Petar K. Shomov wrote:
I think all you expected from the guys that looked at your class to be stunned with your exceptional C++ skills.

How did you reach that ridiculus conclusion? just because I counter-argued your "arguments"?

Petar K. Shomov wrote:
I totally stand by all the points I made in my first post here.

Yeah, right. Every time a guy is cornered and can't defend his initial arguments, all I get is "I stand by all the points." Who cares? you do that. It's not my fault if you can't support your claims.

Petar K. Shomov wrote:
I see that you are not inclined in reading books about C++

You don't know what I have read. How do you know what I have read and what not?

Let me give you an advice: it's not good to make conclusions about others with your own perception.


Petar K. Shomov wrote:
I hope you will consider the possibility to click on this

I read artima forums quite often. But I stand away from too much theory. Endlessly speculating on IS-A and HAS-A is useless: let me see those people that talk about IS-A and HAS-A relationships implement properties, and then we can talk.

Here is hint for you: I chose inheritance because it makes it easier for me: I don't have to write wrapper methods for accessing the member variables.

I did this:
class Foo {
public:
   int data();
};

class Bar : public Foo {
public:    
};


instead of this:

class Foo {
public:
   int data();
};

class Bar {
public:    
   int data() { return foo.data(); }

private:
    Foo foo;
};


Petar K. Shomov wrote:
o at least all this typing (and trying too hard to be sm@rtass) was not a waste.


at least some self-awareness.
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.