Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile

Properties in C++

3.31/5 (15 votes)
20 Dec 2006CPOL4 min read 2   328  
Simulating C# Properties in C++

Introduction

When I was writing a property using C#, I wondered why such a feature doesn't exist in C++? It was a challenging question and because I know how such a thing is important to C++ developers, I spent three days developing this article. I hope you will find it useful as I thought.

What Properties Are

Properties are like variables that store data, but they trigger events that fire while reading or writing data from it. In another words, property is an interactive variable evaluating itself and having different values while reading and writing to it.

It's easy to write a class using language like C# that contains properties but it seems impossible with C++. This is because C++ compiler doesn't support properties like C#. For this reason, I have written this article to show you how to write C++ classes having properties like that of C#.

This document will show you how to use the macros that were written to declare and implement properties. If you are an expert C++ developer and you need to understand how it works, you will not face any problem in reading the macros defined in "Properties.h".

Why Properties are Important

Let's imagine that we need to write an object that represents a person. This object may contain data like:

  • Full Name
  • Age
  • Year of birth
  • Gender

It could be written using C++ as shown below:

C++
class Person {
public:
    Person( ){}
    virtual ~Person( ){}

private://data members

    char m_fName[20];
    char m_lName[20];

    UINT m_YearOfBirth;
    bool m_bGender;
};

NOTE: In most cases, we can't define data member as public to be used directly because data member should be maintained through the business logic which is implemented by the object.

Now if we need to get or set the value of m_bGender, we need to implement methods as shown below:

C++
class Person {
public:
    Person( ){}
    virtual ~Person( ){}
    
    void SetGender(bool bGender) {m_bGender = bGender;}
    bool GetGender() {return m_bGender;}

private://data members

    char m_fName[20];
    char m_lName[20];

    UINT m_YearOfBirth;
    bool m_bGender;
};

The disadvantage of using this method is that you need to know which method should be used to change the Gender. But with properties, life is better because to do the same thing all you need is to know is the name of the property you need. Also a single property can support different data types, in other words in our example we can let Gender accept string and Boolean values use it as shown below.

C++
Person.Gender = "Male";

or

C++
Person.Gender = true;

Of course life now becomes much easier with Properties and the code now also becomes more readable.

Property Declaration

Now I will show you how to write properties. Let's start with writing Gender property as shown below:

C++
class Person {
public:
    Person( ){}
    virtual ~Person( ){}
    
    Begin_Property(char*,Gender)
        __get(char*,Gender)
        _set(char*);

        _get(bool);
        _set(bool);

        __release(Gender)
    End_Property(Gender)

private://data members

    char m_fName[20];
    char m_lName[20];

    UINT m_YearOfBirth;
    bool m_bGender;
};

Now let's look at the code. I started with Property definition using Begin_Property macro which takes two parameters, property data type and property name. Because Gender property is a string property, it should be char*. After I started defining my property, I need to declare the events get(ers) and set(ers) which will fire each time it's being used as shown below:

C++
Person.Gender = true; // This will fire _set(bool) event
bool gender = Person.Gender ; // this will fire _get(bool) event
Person.Gender = "Male"; //This will fire _set(char*)
printf("Gender :%s\n",(char*)Person.Gender); //This will fire _get(char*)

_get and _set are two macros which take one parameter that represents the data types that can be accepted by the property. You can notice the data type of _set and _get events independent of the data type of property. In other words, although the data type "Gender" property is char*, it has bool getters and setters. In this way, it can accept as Boolean or string values as shown above.

The last two macros I used are _release to release the memory it allocates (will be covered in detail later) and End_Property to close property declaration and both macros take property name as a parameter.

Property Implementation

After declaring Properties, we need to implement set(ers) and get(ers). We can do so in the same place as shown below:

C++
.
.
.

Begin_Property(char*,Gender)
    __get(char*,Gender)
    _set(char*)
    {
       //do something hear
       return Gender;
    }

    _get(bool)
    {
      //do something hear
      return iValue;
    }
    _set(bool)
    {
      //do something hear
      return iValue;
    }

    __release(Gender)
End_Property(Gender)
.
.
.

Or implement it using implementation macros, but before showing you how to use those macros, let's discuss two other points, what macro __get is? and why set(ers) should return value? Well, all we need to do in _get(char*) is just return a pointer to it this way "return Gender;" and this is what __get does. __get is the default getter of the Property and because "Gender" is a char* property, we used it in this way "__get(char*,Gender)".

Let's switch to the second question, why set(ers) should return a value like get(ers)? Simply in C++, set(ers) can act as get(ers) as shown below:

C++
bool bGender = Person.Gender = true;

Now let's implement Gender Property using Imp_set and Imp_get macros. Both macros take three parameters data type, Class name and property name as shown below:

C++
Imp_set(char*,Person,Gender)
{
  PROPERTY_PROLOGUE(Person,Gender)
            
  if (!Gender) Gender = new char[7];

  if (strlen(iValue)<6 )
  {     
    int result;
    if ((result=strcmp(iValue,"Male"))==0)
    pThis->m_bGender = true;
    else
    {
      if ((result=strcmp(iValue,"Female"))==0)
        pThis->m_bGender = false;
    }
    
    if(result==0) strcpy(Gender,iValue);
  }
  return Gender;
}

Imp_set(bool,Person,Gender)
{
  PROPERTY_PROLOGUE(Person,Gender)

  if (!Gender) Gender = new char[7];

  if (pThis->m_bGender = iValue)
    strcpy(Gender,"Male");
  else
    strcpy(Gender,"Female");
  
  return (bool)iValue;
}

Imp_get(bool,Person,Gender)
{
  PROPERTY_PROLOGUE(Person,Gender)
  return pThis->m_bGender;
}

Because set(ers) and get(ers) can't access class members directly, we used PROPERTY_PROLOGUE macro. It defines a pointer to the class of the property as shown above called "pThis".

Also in class termination, we need to free the memory and any allocated resources being used by the property, this is the function __release macro. __release is a default release macro and its job is done as shown below:

C++
if (Gender)
{
  delete Gender;
  Gender = NULL;
}

We can also implement release events ourselves using _release and Imp_release as shown below:

C++
Imp_release(Person,Gender)
{
// Release allocated resources here.
}

The Demo Project

This project demonstrates how to write properties and how properties can affect each other. For example, in the person class, the YearOfBirth property changes the age value property and vice versa. Also you can use class as property datatype, for example, I used CTime as a datatype of "LeaveDate" and "ContractDate" properties.

Finally ... I hope I have covered the subject as much as I could. For any inquiries, feel free to contact me. Thanks a lot.

History

  • 20th December, 2006: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)