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

Properties in C++ just like in C# or Delphi

3.00/5 (8 votes)
6 Jul 2008CPOL3 min read 1   256  
Two simple property classes easying C++ programming

Brief description

The header file properties.h contains two template classes: property_t - for implementing properties of any type and property_it - for implementing indexer properties. Both classes has rich set of various methods for binding them with getter and/or setter methods and/or with class fields. Above mentioned file contains also serie definitions for standard C types, e.g. CIntProperty for int type and serie definitions for MFC types, e.g. CStringProperty for CString class.

Using the code

In order to using properties you must include properties.h file first and declare using namespace properties where properties defined are.

C++
#include "properties.h"
using namespace properties;
In your class file you must define class field of type property. It may be one of predefined property type or implicit template declaration.
C++
class SomeClass {
  CIntProperty Integer; // predefined property type
  CDoubleProperty Double; // predefined property type
  property_t<SomeType> someType; // implicit template declaration
};
Syntax of property is very simply, just with template type you declare type of property. Syntax of indexed property is similar with one differece, that template has two type arguments, where first is type of index and second is type of element. It looks as follows:
C++
property_it< int, char > SomeCharIndexer;
Now you must decide in how way you want bind you property. property_t class is able to bind with getter and/or setter methods and getter and/or setter class fields. In this case you must declare field or method or both to which property will be bind. For example you can bind property to getter field and setter method or with only getter and setter fields (usually it is the same field) or with only getter and setter method.
Properties can be bind in followed ways:
  • only getter method
  • only setter method
  • only getter field
  • only setter field
  • getter method and setter method
  • getter method and setter field
  • getter field and setter field
  • getter field and setter method
  • analogous to above combinations with bindings from another the same type property
Indexers properties can be bind only with methods. In order to associate property with her coresponding field or method use one of overloaded bind method. Each of bind method as first parameter take unsigned long offset, which is a offset a field or method in class declaring property. Next parameters depend on way of property binding. For binding with methods it must be one of getter type or setter type method pointer and for field it must be field class pointer.
For non-indexed properties getter and setter methods are always type of:
C++
TYPE getter_method_name(); // for getter
void setter_method_name(const TYPE& value); // for setter
, where TYPE is property type.

For indexed properties getter and setter methods are always type of:
C++
TYPE getter_indexer_method_name(const INDEX& index); // for getter
void setter_indexer_method_name(const INDEX& index, const TYPE& value); // for setter
, where INDEX is a index type and TYPE is a type of indexed element.

And now simple example ilustrating property binings:
C++
int m_integer;
double m_double;
char *m_array;
void set_Integer(const int& value) { m_integer = value; }
double get_Double() { return 3.1415926; }
char get_SomeCharIndexer(const int& index) { return m_array[index]; }
void set_SomeCharIndexer(const int& index, const char& value) { m_array[index] = value; }
/* ... */
BIND_PROPERTY(SomeClass, Double, get_Double, m_double);
BIND_PROPERTY(SomeClass, Integer, m_integer, set_Integer);
BIND_PROPERTY(SomeClass, SomeCharIndexer, get_SomeClassIndexer, set_SomeClassIndexer);
The BIND_PROPERTIES macro is evolved to:
C++
#define BIND_PROPERTY(class_name,prop_name,getter,setter) \
  prop_name.bind(class_name,prop_name,&class_name::getter,&class_name::setter)
Without this macro you must use full syntax, eg:
C++
SomeClassIndexer.bind(offsetof(SomeClass,SomeClassIndexer), &SomeClass::get_SomeClassIndexer, &SomeClass.set_SomeClassIndexer);
At now we consider that you want to write a some control class with interface built with properties. In Microsoft Visual Studio environment your code might be looks as follows:
C++
#include "stdafx.h"
#include "properties.h"

using namespace properties;

class SomeControl
{
protected:
  // getter properties methods
  virtual CPoint get_Location() { /* */ }
  virtual int get_Width() { /* */ }
  virtual int get_Height() { /* */ }
  virtual CString get_Caption() { /* */ }
  virtual CWnd* get_Controls(const int& index) { /* */ }
  
  // setter properties methods
  virtual void set_Location(const CPoint& value) { /* */ }
  virtual void set_Width(const int& value) { /* */ }
  virtual void set_Height(const int& value) { /* */ }
  virtual void set_Caption(const CString& value) { /* */ }
  virtual void set_Copntrols(const int& index, CWnd* const& value) { /* */ }
public:
  SomeControl() {
    BIND_PROPERTY(SomeControl, Location, get_Location, set_Location);
    BIND_PROPERTY(SomeControl, Width, get_Width, set_Width);
    BIND_PROPERTY(SomeControl, Height, get_Height, set_Height);
    BIND_PROPERTY(SomeControl, Caption, get_Caption, set_Caption);
    BIND_PROPERTY(SomeControl, Controls, get_Controls, set_Controls);
  }

  property_t<CPoint>     Location;
  CIntProperty           Width;
  CIntProperty           Height;
  CStringProperty        Caption;
  property_it<int,CWnd*> Controls;
};

Final usage

In any place of code you can change caption, location and dimension of your control:

C++
SomeControl sc;
/* ... */
sc.Caption = "My control with properties";
sc.Location = CPoint(100,100);
sc.Width = 300;
sc.Height = 200;

Remarks

You must remeber that property which has no getter and occurs taking her value or which has no setter and occurs assigning it, then will be throw exception of type char*.

Disclaimer

THE SOFTWARE AND THE ACCOMPANYING FILES ARE DISTRIBUTED "AS IS" AND WITHOUT ANY WARRANTIES WHETHER EXPRESSED OR IMPLIED. NO REPONSIBILITIES FOR POSSIBLE DAMAGES OR EVEN FUNCTIONALITY CAN BE TAKEN. THE USER MUST ASSUME THE ENTIRE RISK OF USING THIS SOFTWARE.

License

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