📜 ⬆️ ⬇️

Property in C ++

Probably, all C ++ language lovers who used other languages, such as C #, are surprised: why there is no property in the pluses? After all, this is really a convenient tool that allows you to fully control access to class members. Recently, I became interested in this issue. Thinking, having looked through Straustrup and finally, having gone through the googling, I came to the conclusion that property can be realized by means of a language. I think many have already seen a variety of implementations, for example, from microsoft , but for someone, I hope this will be an interesting discovery.
In the article you will find one of the possible options for the implementation of properties using templates.

Formulation of the problem


To begin, we define what we want. And we want the property to be accessed as an ordinary field of an object through a point (well, or ->) both for writing and for reading and without any brackets. That is, like this:

a.property = value;
MyClass var = a.property;

In this case, the setter and getter functions defined by us must be called. I would also like the property to be defined in the class as simple and clear as possible.

Implementation


We see that if a.property is an instance of the property class defined by us, then you can overload the operator =, getting a setter, as well as a type conversion operator, getting a getter. The class itself must be template-based to allow the use of properties of any type.
In order not to implement its own class for each property, overloaded operators must make a function call on the pointer passed to the property in the constructor.
For use, we declare a variable of our type Property as a public field in the class and pass the type we need as the first parameter of the template, and pointers to functions in the parameters of the constructor.
')
When all this was implemented, another remarkable property feature was remembered: it can be Read Only. Before that, only a full-fledged property with a setter and a getter was considered. And it is important that the read and write permissions are checked at compile time. This is where template specializations come to the rescue. You can implement three different classes (read and write, read only, write only) Property with the same name, differing in the template parameter, the so-called specialization. The final implementation looks like this:
 #pragma once #define NULL 0 class ReadOnly; class WriteOnly; class ReadWrite; template <typename Type, typename Owner,typename Access> class Property { }; template<typename Type, typename Owner> class Property<typename Type, typename Owner, ReadWrite> { protected: typedef Type (Owner::*getter)(); typedef void (Owner::*setter)(Type); Owner * m_owner; getter m_getter; setter m_setter; public: //   .  . operator Type() { return (m_owner->*m_getter)(); } //  .  . void operator =(Type data) { (m_owner->*m_setter)(data); } Property() : m_owner(NULL), m_getter(NULL), m_setter(NULL) { } Property(Owner * const owner, getter getmethod, setter setmethod) : m_owner(owner), m_getter(getmethod), m_setter(setmethod) { } void init(Owner * const owner, getter getmethod, setter setmethod) { m_owner = owner; m_getter = getmethod; m_setter = setmethod; } }; template<typename Type, typename Owner> class Property<typename Type, typename Owner, ReadOnly> { protected: typedef Type (Owner::*getter)(); Owner * m_owner; getter m_getter; public: //   .  . operator Type() { return (m_owner->*m_getter)(); } Property() : m_owner(NULL), m_getter(NULL) { } Property(Owner * const owner, getter getmethod) : m_owner(owner), m_getter(getmethod) { } void init(Owner * const owner, getter getmethod) { m_owner = owner; m_getter = getmethod; } }; template<typename Type, typename Owner> class Property<typename Type, typename Owner, WriteOnly> { protected: typedef void (Owner::*setter)(Type); Owner * m_owner; setter m_setter; public: //  .  . void operator =(Type data) { (m_owner->*m_setter)(data); } Property() : m_owner(NULL), m_setter(NULL) { } Property(Owner * const owner, setter setmethod) : m_owner(owner), m_setter(setmethod) { } void init(Owner * const owner, setter setmethod) { m_owner = owner; m_setter = setmethod; } }; 


Using


You can use it like this:
TestClass.h file
 #pragma once #include "Property.h" class TestClass { public: TestClass(void); ~TestClass(void); void _setterRW(int a); int _getterRW(); Property<int, TestClass, ReadWrite> testRW; int _getterRO(); Property<int, TestClass, ReadOnly> testRO; void _setterWO(int a); Property<int, TestClass, WriteOnly> testWO; private: int propRW; int propRO; int propWO; }; 


TestClass.cpp file

 #include "TestClass.h" TestClass::TestClass(void) { testRW.init(this, &TestClass::_getterRW, &TestClass::_setterRW); testRO.init(this, &TestClass::_getterRO); propRO = 123; testWO.init(this, &TestClass::_setterWO); } int TestClass::_getterRW() { return propRW; } void TestClass::_setterRW(int a) { propRW = a; } int TestClass::_getterRO() { return propRO; } void TestClass::_setterWO(int a) { propWO = a; } TestClass::~TestClass(void) { } 


Main.cpp file
 #include "TestClass.h" #include "stdio.h" int main() { TestClass t; t.testRW = 15; int a = t.testRW; t.testWO = 34; //a = t.testWO; //:  WriteOnly property //t.testRO = 45; //:   ReadOnly property printf("RW = %d\n", int(t.testRW)); printf("RO = %d\n", int(t.testRO)); scanf("%d", a); return 0; } 

Conclusion


This implementation suits me, but I do not like it for several reasons. The first is the need to specify the class to which the property belongs. The second is the need to initialize each property in the constructor, and that is, at the execution stage. The third is the impossibility of creating a static property. Well, the fourth, less significant: the prompter shows the type of Property, and not the fact that we write there, which may cause some questions to the one who sees it for the first time. Also, the topic of pointers to class methods is very muddy, poorly disclosed and little used. It is well explained here , but the most important thing is that I realized that it is necessary to use them very carefully.
It turned out not so intuitive to use as I wanted, but the goal was achieved.

Used materials:
www.rsdn.ru/article/vcpp/props.xml - the main ideas.
www.rsdn.ru/forum/cpp/854559.1.aspx - an idea with access rights.
rsdn.ru/article/cpp/fastdelegate.xml - a detailed explanation of pointers to functions and methods of classes in C ++.

Sources with examples here .
Visual Studio 2008 project is here .

This text is published under the license CC-BY .

Original article can be found here . Copypaste is made consciously, since the topic should be interesting to the habranelene, and the site on which the article was originally published is not able to withstand even a small influx of visitors due to hosting.

Source: https://habr.com/ru/post/121799/


All Articles