Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#

C++ Properties

Rate me:
Please Sign up or sign in to vote.
4.89/5 (42 votes)
18 Oct 2010CPOL5 min read 249.4K   71   62
C#-Style Properties in C++

Introduction

This article discusses how to implement C#-like properties in Visual C++ 6 or above. This article assumes that the reader has enough knowledge in the C++ language to understand the code (though the code snippet will be thoroughly explained). It is recommended that the reader understands macros, classes, functions, and typedefs; however, this code is available for anyone to use.

Background

If you are a new C++ or C# programmer, then properties may be a new concept. Properties are simply a convenient way of defining a getter and a setter for a given member variable. A getter is a member function that returns the literal value of the member variable that the property represents. The setter sets the literal value of the member variable that the property represents, but does not return a value. Properties in C# typically look like the following:

C#
private int _x;
public int x
{
	get
	{
		return _x;
	}
	set
	{
		_x = value;
	}
}  

Of course, get designates the getter and set designates the setter. Within the setter, a variable labeled value exists that represents the rvalue of an assignment statement that involved your property. For example, in the following code snippet, the value variable would contain the value 50.

C#
someObject.x = 50;  

When the property is assigned a value, as in the above example, the setter member function is called and passed the rvalue as an argument to a parameter labeled value. Of course, the simplicity of properties allow us to not worry about the definition of these member functions and hides the actual calling of the function from us. We simply declare the getters and setters using the get and set keywords in C#.

Properties in C++

Unfortunately, C++ does not natively support properties. Properties in C++ involve writing out each function for each setter and getter. For example, the following code implements the same property as above, but in C++.

C++
private: 
 	int x; 
public:  
 	int getX()
 	{
  		return x;
  	}
   	void setX(int value) 
   	{
   		x = value;
        }    

In order to use the setter and getter, we simply call the corresponding member function.

C++
someObject.setX(50);  
int x = someObject.getX();  

The above code is perfectly fine and many people prefer these setters and getters as opposed to the C#-styled ones; however, there also exist many people who want C#-styled properties in C++. Because of this, Visual C++ 6.0 and above decided to implement a property declaration attribute.

C++
__declspec( property (put=setFunction, get=getFunction) ) data-type property-name; 

The above code allows us to tell Visual C++ that we want setFunction to be called every time property-name is assigned to. Conversely, we want getFunction to be called every time we need to get the value of property-name. Of course, we still have to define those member functions, but this brings us much closer to implementing C#-style properties.

(A small note to non-Visual C++ users: implementing these properties is possible; however, it requires a much higher level or work and this article does not address it.)

The Implementation

Of course our C++ implementation will not be the exact syntax as C# properties for obvious reasons, but nonetheless it is a close representation. Below is the only code you will need in order to implement properties in Visual C++.

C++
#define PROPERTY(t,n)  __declspec( property 
	( put = property__set_##n, get = property__get_##n ) ) t n;\
	typedef t property__tmp_type_##n
#define READONLY_PROPERTY(t,n) __declspec( property (get = property__get_##n) ) t n;\
	typedef t property__tmp_type_##n
#define WRITEONLY_PROPERTY(t,n) __declspec( property (put = property__set_##n) ) t n;\
	typedef t property__tmp_type_##n
#define GET(n) property__tmp_type_##n property__get_##n() 
#define SET(n) void property__set_##n(const property__tmp_type_##n& value)   

At first sight, this code may look frightening, but fear not. The above code is extremely easy to use. To declare a property using these macros, we simply use one of the PROPERTY macros. Below is a sample implementation of the sample property used earlier.

C++
private: 
	int _x; 
public:  
 	PROPERTY(int, x);
  	GET(x) 
 	{ 
 		return _x; 
	}
 	SET(x)
 	{
 		_x = value;
 	}   

And just as in C#, we can access our property like the following:

C++
someObject.x = 50;
int x = someObject.x; 

When we assign a value to the <code>x property, the rvalue (which is 50 in this example) is assigned to the variable value, which is accessible in the setter. The code within the setter is then executed. When we get the value of the property, the code within our getter is executed and a value is returned (in this case, the value of _x).

Read-Only, Write-Only, and Access Modifiers

The above code natively supports read-only, write-only, and access-modified properties. Each of the different types of properties have their own uses. For example, a read-only property should only be used if neither the parent class nor any object accessing the property does not need to write to the property. Conversely, write-only should only be used if neither the parent class nor any object accessing the property does not need to read from the property. In order to use read-only and write-only properties, we simply use the corresponding macro and only define the corresponding setter or getter. Below is an example of each.

C++
 // read-only   
READONLY_PROPERTY(int, length);  
GET(length) 
{ 
	return strlen(someString); 
}  
C++
// write-only (rare)
WRITEONLY_PROPERTY(int, size);  
SET(size) 
{ 
	_size = value;
}   

Typically, neither read-only nor write-only properties are used. It is much more common to change the access-modifier of a property. Changing the access modifier of a property simply means to make it public, private, protected, etc. It is common for read-only properties to be implemented by simply making the setter private. However, the getter and setter do not need to be declared with the same access-modifier. For example, the getter can be public while the setter can be private. Likewise, the getter can be private and the setter can be public.

Full Example

screen2.png

When learning any new concept, it helps to see a fully working example.

C++
// properties.h

#ifndef _PROPERTIES_H
#define _PROPERTIES_H

#define PROPERTY(t,n)  __declspec( property 
	( put = property__set_##n, get = property__get_##n ) ) t n;\
	typedef t property__tmp_type_##n
#define READONLY_PROPERTY(t,n) __declspec( property (get = property__get_##n) ) t n;\
	typedef t property__tmp_type_##n
#define WRITEONLY_PROPERTY(t,n) __declspec( property (put = property__set_##n) ) t n;\
	typedef t property__tmp_type_##n

#define GET(n) property__tmp_type_##n property__get_##n()
#define SET(n) void property__set_##n(const property__tmp_type_##n& value)

#endif /* _PROPERTIES_H */ 
C++
// main.cpp
#include <iostream>

#include <math.h>

#include "properties.h"

class Vector2
{
public:
	float x;
	float y;

	READONLY_PROPERTY(float, Length);
	GET(Length) 
	{ 
		return sqrt((x*x + y*y));
	}
};

int main()
{
	Vector2 vec;
	vec.x = 1;
	vec.y = 1;
	std::cout << "Length of vector(" << vec.x << ", " << vec.y << ") = ";
	std::cout << vec.Length << "\n"; // <--- property, not a function call

	return 0;
}  

The above code works with any Visual C++ version above 6.0. It does not need any additional dependencies -- as the section title states, it is a full example.

How It Works

Now let us move on to the nitty-gritty. The way these properties actually work lie in the magic of C++ macros. Let us take our original C++ property example and see what our macros would actually generate.

C++
private: 
	int _x; 
public:  
 	PROPERTY(int, x);
  	GET(x) 
 	{ 
 		return _x; 
	}
 	SET(x)
 	{
 		_x = value;
	}  

The above code is not what the compiler actually sees after preprocessing is complete. We must replace our PROPERTY, GET, and SET with the expanded form of the macro. The expanded version would look like the following:

C++
private: 
	int _x; 
public:  
	__declspec(property(put = property__set_x, get = property__get_x)) int x;
	typedef int property__tmp_type_x;

	property__tmp_type_x property__get_x()
	{
		return _x;
	}

	void property__set_x(const property__tmp_type_x& value)
	{
		_x = value;
	}   

As you can see, our GET and SET macros expand to member functions, just like they do in C#. However, this is hidden from us when we use our macros so it appears more C#-like.

Conclusion

Many people seem to argue about whether it is better to use properties or simply use getter and setter member functions in C++. The simple fact is that both are using member functions to perform the getting and setting, and as such, neither have any runtime performance gain over the other -- they are exactly the same.

History

  • October 17, 2010 -- Posted original article
  • October 17, 2010 -- Added screenshot of full example

License

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


Written By
Instructor / Trainer
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

 
GeneralRe: My vote of 2 Pin
Stefan_Lang17-Jun-15 0:46
Stefan_Lang17-Jun-15 0:46 
GeneralMy vote of 3 Pin
Jaded Hobo2-Nov-10 9:35
Jaded Hobo2-Nov-10 9:35 
GeneralRe: My vote of 3 Pin
jorgy3432-Nov-10 11:57
jorgy3432-Nov-10 11:57 
GeneralRe: My vote of 3 Pin
peterchen11-Oct-12 22:34
peterchen11-Oct-12 22:34 
GeneralMy vote of 4 Pin
Martin Richter [rMVP C++]1-Nov-10 4:21
Martin Richter [rMVP C++]1-Nov-10 4:21 
GeneralMy vote of 5 Pin
Harrison H26-Oct-10 6:22
Harrison H26-Oct-10 6:22 
GeneralBad Idea Pin
SeattleC++20-Oct-10 12:58
SeattleC++20-Oct-10 12:58 
GeneralRe: Bad Idea Pin
yarp20-Oct-10 20:10
yarp20-Oct-10 20:10 
GeneralRe: Bad Idea Pin
jorgy34324-Oct-10 9:26
jorgy34324-Oct-10 9:26 
GeneralRe: Bad Idea Pin
yarp24-Oct-10 18:59
yarp24-Oct-10 18:59 
GeneralRe: Bad Idea Pin
jorgy34325-Oct-10 8:39
jorgy34325-Oct-10 8:39 
GeneralRe: Bad Idea Pin
yarp25-Oct-10 18:08
yarp25-Oct-10 18:08 
GeneralRe: Bad Idea Pin
ccoale42726-Oct-10 12:41
ccoale42726-Oct-10 12:41 
GeneralRe: Bad Idea Pin
jorgy34330-Oct-10 10:12
jorgy34330-Oct-10 10:12 
GeneralRe: Bad Idea Pin
David Crow9-Nov-10 4:41
David Crow9-Nov-10 4:41 
GeneralRe: Bad Idea Pin
jorgy34325-Oct-10 9:12
jorgy34325-Oct-10 9:12 
GeneralRe: Bad Idea Pin
soren.fog.ubs17-Nov-10 18:52
soren.fog.ubs17-Nov-10 18:52 
Generalusage get/set Pin
filippov.anton18-Oct-10 16:11
filippov.anton18-Oct-10 16:11 
GeneralRe: usage get/set [modified] Pin
ccoale42718-Oct-10 18:58
ccoale42718-Oct-10 18:58 
GeneralC++ properties Pin
geoyar18-Oct-10 15:36
professionalgeoyar18-Oct-10 15:36 
GeneralRe: C++ properties Pin
ccoale42718-Oct-10 19:05
ccoale42718-Oct-10 19:05 
GeneralRe: C++ properties [modified] Pin
jorgy34324-Oct-10 9:15
jorgy34324-Oct-10 9:15 
GeneralGreat! Almost as elegant as C++/CLI properties Pin
Attila Kúr18-Oct-10 10:49
Attila Kúr18-Oct-10 10:49 
GeneralFYI Pin
Fazlul Kabir18-Oct-10 10:27
Fazlul Kabir18-Oct-10 10:27 
Generalunportable and unsafe...but still inspires me PinPopular
Kevin Drzycimski18-Oct-10 9:22
Kevin Drzycimski18-Oct-10 9:22 

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.