Click here to Skip to main content
15,881,852 members
Articles / Programming Languages / C++
Tip/Trick

CSharpish Properties in Modern C++

Rate me:
Please Sign up or sign in to vote.
5.00/5 (10 votes)
25 Oct 2020CPOL3 min read 11.8K   12   13
Simple trick to implement csharpish properties in modern C++
C# has properties that behave like class member variables and capture read and write operations. We can implement similar behavior in modern C++ in only 15 lines of code.

Introduction

Traditionally, variables have been used as a space for storing and reading values. With evolution of programming, it was discovered that being able to do something when we store a value into a variable or read from it is quite practical. Today, most modern languages support this via properties.

In C#, a property has two pseudo functions that implement reading and writing. They are called a getter and a setter. Inside the setter, you can use a special keyword called value. It holds the desired value that we want to assign to the property.

This is how your average C# property looks like:

C#
public class Person {
    private int _age;
    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }
}

In this example, the getter simply returns the value of persons' age, stored in the private member variable _age. And the setter assigns the previously mentioned value to a private variable _age.

We would like to re-create this in Modern C++.

The Solution

Mimic Native Type

An int property class should behave like an int. Hence, our first task is to make our property class behave like its type. This can be done with a combination of a template, an implicit cast and an assignment operator.

So let's define the template that roughly behaves like a native type.

C++
template<typename T>
class property {
    operator T() const { return /* return property value */ };
    property<T>& operator= (const T& value) { /* set your value */ }
}

We can now use our C++ property like this:

C++
property<int> i;
i=10;     // Calls the assignment operator=.
int j=i;  // Calls the T() implicit cast.

Pass Setter and Getter

In the previous chapter, we discovered how we can capture get and set operations by implementing an implicit cast and an assignment operator. Now let us enable passing a custom setter and the getter functions to our properties.

This is a job for lambda expressions. To be able to define properties directly in C++ header files, let's pass getter and setter functions to a property via the constructor:

C++
#include <functional>

template<typename T>
class property {
public:
    property(
        std::function<void(T)> setter,
        std::function<T()> getter) :
        setter_(setter),getter_(getter) { }
    operator T() const { return getter_(); }
    property<T>& operator= (const T &value) { setter_(value); return *this; }
private:
    std::function<void(T)> setter_;
    std::function<T()> getter_;
};

With this addition, we're almost there. In fact, if we only need to capture storing and reading values from the property, we are already there.

To fully mimic the C# property, we still need to implement that special value member though.

The Value

Let's add a private member variable of template type T to the property class and call it value_. To access this value, let's use a really dirty trick that will raise some eyebrows. Let's create a function value() that simply returns a reference to private member value_. Why? Because this way, we can assign to that property member variable directly - bypassing getters and setters, just like we can assign to a private class member variable in C#.

This is the final property class after adding a private variable value_ of type T and a function T& value() that returns a reference to it.

C++
#include <functional>

template<typename T>
class property {
public:
    property(
        std::function<void(T)> setter,
        std::function<T()> getter) :
        setter_(setter),getter_(getter) { }
    operator T() const { return getter_(); }
    property<T>& operator= (const T &value) { setter_(value); return *this; }
    T& value() { return value_; }
private:
    std::function<void(T)> setter_;
    std::function<T()> getter_;
    T value_;
};

And we're done!

Using Properties

We can define our sample property in C++ like this:

C++
class person {
public:
property<int> age {
    [this] (int x) { this->age.value()=x; },        // Setter ... yes you can do this!
    [this] () -> int {  return this->age.value(); } // Getter.
    };
};

And use it as an integer in the rest of our code:

C++
person p;
p.age=10;         // Call setter.
std::cout<<p.age; // Call getter.

Known Issues

To completely mimic underlying type, our property class could override and pass other operators like ++,--,+=. In addition, the class could be separated to base class without the value_ called property, and a derived class with a value_ member called value_property.

History

  • 25th October, 2020: Initial version

License

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


Written By
Founder Wischner Ltd
United Kingdom United Kingdom
Writing code since 1982 and still enjoying it.

Comments and Discussions

 
Suggestionhow about set default setter and getter? Pin
fatming29-Oct-20 19:53
fatming29-Oct-20 19:53 
GeneralRe: how about set default setter and getter? Pin
Tomaž Štih8-Nov-20 6:22
Tomaž Štih8-Nov-20 6:22 
SuggestionGetter should probably return T& Pin
Karel Donk26-Oct-20 6:36
Karel Donk26-Oct-20 6:36 
QuestionJust make the member public? Pin
Greg Utas26-Oct-20 1:03
professionalGreg Utas26-Oct-20 1:03 
AnswerRe: Just make the member public? Pin
Tomaž Štih26-Oct-20 1:43
Tomaž Štih26-Oct-20 1:43 
GeneralRe: Just make the member public? Pin
Greg Utas26-Oct-20 2:20
professionalGreg Utas26-Oct-20 2:20 
GeneralRe: Just make the member public? Pin
Tomaž Štih26-Oct-20 2:56
Tomaž Štih26-Oct-20 2:56 
AnswerRe: Just make the member public? Pin
Mike Diack26-Oct-20 6:35
Mike Diack26-Oct-20 6:35 
GeneralRe: Just make the member public? Pin
Greg Utas26-Oct-20 6:42
professionalGreg Utas26-Oct-20 6:42 
AnswerRe: Just make the member public? Pin
chris Bruner26-Oct-20 6:53
chris Bruner26-Oct-20 6:53 
GeneralRe: Just make the member public? Pin
Greg Utas26-Oct-20 7:08
professionalGreg Utas26-Oct-20 7:08 
GeneralMy vote of 5 Pin
Сергій Ярошко26-Oct-20 0:16
professionalСергій Ярошко26-Oct-20 0:16 
PraiseGot my 5 Pin
Shao Voon Wong25-Oct-20 22:55
mvaShao Voon Wong25-Oct-20 22:55 

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.