Click here to Skip to main content
15,881,173 members
Articles / Programming Languages / C++
Article

Implementing Properties In C++

Rate me:
Please Sign up or sign in to vote.
4.56/5 (48 votes)
2 Apr 20034 min read 212.7K   1K   53   52
Implementing properties on c++ objects

Introduction

This project tries to simulate the property behaviors that exist in C# (and other languages...) in C++ without using any extensions. Most libraries or compilers that implement properties in C++ use extensions such as Managed C++ or C++ Builder or they use set and get methods which look like normal methods rather than properties.

Let us first see what a property is. A property acts like a field or member variable from the point of view of the library user, but it accesses the underlying variable through read or write methods or set or get methods.

For example, I have class A and property Count, I can write the following code.

C++
A foo;
    
cout <<  foo.Count;

The Count property actualy calls the get function to return the value of the required variable. One of the main advantage of using properties instead of directly accessing the variable is that you can set the property as read only (where you are only allowed to read the variable, not change it), write only or both read write, so let us implement it.

We need to be able to do the following.

C++
//-- Will call the get function to get the underlying value
int i = foo.Count;

//-- Will call the set function to set the value
foo.Count = i;

So it is obvious that we need to overload the = operator for setting the variable and also the return type (which we will show a little later).

We will implement a class called property which will act exactly like a property, as the following example shows.

C++
template<typename Container, typename ValueType, int nPropType>
    class property {}

This Template class will represent our property. The Container is the type of the class that will contain the variable, the set & get methods and the property. ValueType is the type of the internal variable itself. nPropType is the access type of the property (read only, write only or read write).

So now we need to set a pointer to the set and get method from the container class to the property and also override the operator = so that the property will act like the variable, so let's see the full listing of the property class.

C++
#define READ_ONLY 1
#define WRITE_ONLY 2
#define READ_WRITE 3

template <typename Container, typename ValueType, int nPropType>
    class property
{
public:
    property()
    {
        m_cObject = NULL;
        Set = NULL;
        Get = NULL;
    }

    //-- Set a pointer to the class that contain the property --
    void setContainer(Container* cObject)
    {
        m_cObject = cObject;
    }

    //-- Set the set member function that will change the value --
    void setter(void (Container::*pSet)(ValueType value))
    {
        if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE))
            Set = pSet;
        else
            Set = NULL;
    }

    //-- Set the get member function that will retrieve the value --
    void getter(ValueType (Container::*pGet)())
    {
        if((nPropType == READ_ONLY) || (nPropType == READ_WRITE))
            Get = pGet;
        else
            Get = NULL;
    }

    //-- Overload the = operator to set the value using the set member --
    ValueType operator =(const ValueType& value)
    {
        assert(m_cObject != NULL);
        assert(Set != NULL);
        (m_cObject->*Set)(value);
        return value;
    }

    //-- Cast the property class to the internal type --
    operator ValueType()
    {
        assert(m_cObject != NULL);
        assert(Get != NULL);
        return (m_cObject->*Get)();
    }

private:
    //-- Pointer to the module that contains the property --
    Container* m_cObject;
    //-- Pointer to set member function --
    void (Container::*Set)(ValueType value);
    //-- Pointer to get member function --
    ValueType (Container::*Get)();};

So now let's examine each piece.

The following code just sets the Container pointer to a valid instance that contains the property we're going to access.

C++
void setContainer(Container* cObject)
{
    m_cObject = cObject;
}

The following code sets a pointer to the get and set member functions of the container class. The only restrictions are that the set member function must take a single parameter and return void and the get member function must take no parameters but return the value type.

C++
//-- Set the set member function that will change the value --
void setter(void (Container::*pSet)(ValueType value))
{
    if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE))
        Set = pSet;
    else
        Set = NULL;
}

//-- Set the get member function that will retrieve the value --
void getter(ValueType (Container::*pGet)())
{
    if((nPropType == READ_ONLY) || (nPropType == READ_WRITE))
        Get = pGet;
    else
        Get = NULL;
}

The first operator in the following code is the = operator, which calls the set member of the container passing the value. The second operator makes the entire property class act as the ValueType so it returns the value returned by the get function.

C++
//-- Overload the = operator to set the value using the set member --

ValueType operator =(const ValueType& value)
{
    assert(m_cObject != NULL);
    assert(Set != NULL);
    (m_cObject->*Set)(value);
    return value;
}

//-- To make possible to cast the property class to the internal type --
operator ValueType()
{
    assert(m_cObject != NULL);
    assert(Get != NULL);
    return (m_cObject->*Get)();
}

Now let's see how to use it.

As shown below, the PropTest class implements a simple property called Count. The actual value will be stored and retrieved from the private member variable m_nCount, through the get and set methods. The get and set methods can have any name as long as their addresses are passed to the property class as shown in the constructor of the PropTest object. The line property<PropTest,int,READ_WRITE> Count; says that we have a read & write property of type integer in class PropTest called Count. Now you can call Count as normal member variable even though you're really calling the set and get methods indirectly.

The initialization shown in the constructor of the PropTest class is necessary for the property class to work.

C++
class PropTest
{
public:
    PropTest()
    {
        Count.setContainer(this);
        Count.setter(&PropTest::setCount);
        Count.getter(&PropTest::getCount);
    }
    
    int getCount()
    {
        return m_nCount;
    }

    void setCount(int nCount)
    {
        m_nCount = nCount;
    }

    property<PropTest,int,READ_WRITE> Count;

private:
    int m_nCount;
};

As shown below you use the Count property as though it were a normal variable.

C++
int i = 5,
    j;

PropTest test;

test.Count = i;    // call the set method --

j = test.Count;    //-- call the get method --

For read only properties you create an instance of the property as follows

C++
property<PropTest,int,READ_ONLY > Count;

And for write only properties you would create an instance of the property as follows

C++
property<PropTest,int,WRITE_ONLY > Count;

Note: If you set the property to read only and you try to assign to it, it will cause an assertion in debug builds. Similarly, if you set the property to write only and you try to read it an assertion will occur in debug builds.

Conclusion:

This shows how to implement properties in C++ using standard C++ without any extensions. Naturally, using set and get methods are more efficient because with this method you have a new instance of the property class per each property.

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
Architect
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generaloverloading &lt;&lt; and >> operator Pin
niko28829-Apr-07 10:01
niko28829-Apr-07 10:01 
GeneralYET A simple way to implement properties.... Pin
AnandChavali21-Dec-06 0:13
AnandChavali21-Dec-06 0:13 
GeneralRe: YET A simple way to implement properties.... Pin
AnandChavali21-Dec-06 0:19
AnandChavali21-Dec-06 0:19 
GeneralA simpler property Pin
Siegfried Bauer4-Oct-04 0:20
Siegfried Bauer4-Oct-04 0:20 
GeneralRe: A simpler property Pin
Emad Barsoum4-Oct-04 6:57
Emad Barsoum4-Oct-04 6:57 
GeneralYour implementation needs some improvements Pin
Ghost-Rider26-Feb-04 22:30
Ghost-Rider26-Feb-04 22:30 
GeneralRe: Your implementation needs some improvements Pin
masud_masud22-Mar-04 10:39
masud_masud22-Mar-04 10:39 
GeneralExtra assignment operator Pin
HChristiaans13-Jul-03 12:55
sussHChristiaans13-Jul-03 12:55 
GeneralRe: Extra assignment operator: like this Pin
cimnik02910-Apr-04 12:09
cimnik02910-Apr-04 12:09 
GeneralRe: Extra assignment operator Pin
Ali Imran Khan Shirani2-Sep-06 22:23
Ali Imran Khan Shirani2-Sep-06 22:23 
AnswerRe: Extra assignment operator Pin
Joseph Maurer24-May-12 6:48
Joseph Maurer24-May-12 6:48 
GeneralA little simplification... Pin
Ken Keray12-Apr-03 13:02
Ken Keray12-Apr-03 13:02 
GeneralRe: A little simplification... Pin
Emad Barsoum12-Apr-03 13:23
Emad Barsoum12-Apr-03 13:23 
GeneralRe: A little ssugestions... Pin
peterchen20-May-03 10:33
peterchen20-May-03 10:33 
GeneralRe: A little ssugestions... Pin
6Qing8826-Apr-09 23:49
6Qing8826-Apr-09 23:49 
a better solution is to keep the size of the container
4byte(sizeof(void*)),
getter,and setter should be written specifically to achieve
automation, that is, not only to perform a simple get and set,
but also to change some other things, a single pointer to the
actual data will saffice, getter and setter are implemented
as member functions of that property. Smile | :)

those with read-only attribute set, can be regarded as they
have only
operator ValType () const;
method.
and so on. Poke tongue | ;-P
GeneralOther implementation Pin
Anders Dalvander9-Apr-03 11:53
Anders Dalvander9-Apr-03 11:53 
GeneralSorry for the long post above Pin
Anders Dalvander9-Apr-03 11:54
Anders Dalvander9-Apr-03 11:54 
General[Message Deleted] Pin
PeterSchregle8-May-03 21:47
PeterSchregle8-May-03 21:47 
GeneralRe: Other implementation Pin
Anders Dalvander8-May-03 23:11
Anders Dalvander8-May-03 23:11 
QuestionCould property own the value? Pin
davidlmontgomery8-Apr-03 21:20
davidlmontgomery8-Apr-03 21:20 
AnswerRe: Could property own the value? Pin
Anders Dalvander9-Apr-03 4:03
Anders Dalvander9-Apr-03 4:03 
GeneralRe: Could property own the value? Pin
davidlmontgomery9-Apr-03 20:08
davidlmontgomery9-Apr-03 20:08 
GeneralRe: Could property own the value? Pin
Anders Dalvander9-Apr-03 22:45
Anders Dalvander9-Apr-03 22:45 
AnswerRe: Could property own the value? Pin
cimnik0299-Apr-04 15:54
cimnik0299-Apr-04 15:54 
GeneralOperator support Pin
Anders Dalvander4-Apr-03 11:15
Anders Dalvander4-Apr-03 11:15 

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.