Click here to Skip to main content
15,880,725 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 250.3K   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

 
QuestionThere is a problem for PROPERTY members when used as reference or return parameters Pin
rmacapobre19-Jun-16 16:35
rmacapobre19-Jun-16 16:35 
GeneralMy vote of 5 Pin
David A. Gray18-Jan-16 13:32
David A. Gray18-Jan-16 13:32 
QuestionMy Vote of 5 Pin
Manikandan1023-May-14 23:44
professionalManikandan1023-May-14 23:44 
GeneralMy vote of 5 Pin
PrafullaVedante18-Apr-13 20:04
PrafullaVedante18-Apr-13 20:04 
GeneralMy vote of 5 Pin
Pokiaka28-Jun-12 2:58
Pokiaka28-Jun-12 2:58 
SuggestionSmall improvements PinPopular
anlarke24-May-12 12:01
anlarke24-May-12 12:01 
GeneralRe: Small improvements Pin
rmacapobre19-Jun-16 16:40
rmacapobre19-Jun-16 16:40 
GeneralBetter than C# Properties Pin
bob1697229-Sep-11 5:59
bob1697229-Sep-11 5:59 
GeneralMy vote of 5 Pin
Paul Heil10-Aug-11 5:17
Paul Heil10-Aug-11 5:17 
GeneralMove on! Pin
Ajay Vijayvargiya13-Jan-11 8:39
Ajay Vijayvargiya13-Jan-11 8:39 
GeneralRe: Move on! Pin
Rob Grainger7-Jul-11 5:24
Rob Grainger7-Jul-11 5:24 
GeneralRe: Move on! Pin
SajeeshCheviry15-Feb-13 17:06
SajeeshCheviry15-Feb-13 17:06 
Generaldecltype Pin
kornman0018-Nov-10 11:34
kornman0018-Nov-10 11:34 
GeneralRe: decltype Pin
Ajay Vijayvargiya13-Jan-11 8:49
Ajay Vijayvargiya13-Jan-11 8:49 
GeneralMy vote of 2 Pin
Alain Rist7-Nov-10 21:53
Alain Rist7-Nov-10 21:53 
GeneralRe: My vote of 2 [modified] Pin
ccoale4278-Nov-10 12:39
ccoale4278-Nov-10 12:39 
What do templates have to do with this? If you are referring to taking a cross-platform approach and implementing properties by means of a templated class, then you should re-read the article, because I clearly point out that this is for Visual C++ only. The template version is slower because it requires a double function call (if the compiler doesn't inline the first one), and multiple moves of a reference. My approach, which takes advantage of Visual C++ specific features, is faster because the get and set is literally replaced with a single function call. There is no passing around references and no instantiating classes.

If you are referring to the standard template library, what does that (again) have to do with this? The two aren't even remotely related. Perhaps you misunderstood my usage case. It was not supposed to be an implementation of the std::vector class, if that is what you thought. It was supposed to be an example implementation of an extremely basic math 2D vector class, something that the STL does not provide. Other than that, I don't know what the STL (or even the C standard library) has to do with my article.

So, I am entirely clueless as to what you mean by your post. Could you please elaborate? Frown | :(
modified on Monday, November 8, 2010 6:48 PM

GeneralRe: My vote of 2 Pin
Alain Rist9-Nov-10 5:03
Alain Rist9-Nov-10 5:03 
GeneralRe: My vote of 2 Pin
ccoale4279-Nov-10 5:39
ccoale4279-Nov-10 5:39 
GeneralRe: My vote of 2 Pin
Alain Rist9-Nov-10 6:26
Alain Rist9-Nov-10 6:26 
GeneralRe: My vote of 2 Pin
jorgy3439-Nov-10 5:53
jorgy3439-Nov-10 5:53 
GeneralRe: My vote of 2 Pin
Alain Rist9-Nov-10 6:57
Alain Rist9-Nov-10 6:57 
GeneralRe: My vote of 2 Pin
ccoale4279-Nov-10 7:01
ccoale4279-Nov-10 7:01 
GeneralRe: My vote of 2 Pin
Alain Rist9-Nov-10 7:29
Alain Rist9-Nov-10 7:29 
GeneralRe: My vote of 2 Pin
ccoale4279-Nov-10 7:35
ccoale4279-Nov-10 7:35 
GeneralRe: My vote of 2 Pin
Alain Rist9-Nov-10 8:22
Alain Rist9-Nov-10 8: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.