|
Introduction
This project tries to simulate the property behaviors that exist in C# (and other languages...) in C++ without using any extensions. Most libraries or compilers that implement properties in C++ use extensions such as Managed C++ or C++ Builder or they use set and get methods which look like normal methods rather than properties.
Let us first see what a property is. A property acts like a field or member variable from the point of view of the library user, but it accesses the underlying variable through read or write methods or set or get methods.
For example, I have class A and property Count, I can write the following code. A foo;
cout << foo.Count;
The Count property actualy calls the get function to return the value of the required variable. One of the main advantage of using properties instead of directly accessing the variable is that you can set the property as read only (where you are only allowed to read the variable, not change it), write only or both read write, so let us implement it.
We need to be able to do the following.
int i = foo.Count;
foo.Count = i;
So it is obvious that we need to overload the = operator for setting the variable and also the return type (which we will show a little later).
We will implement a class called property which will act exactly like a property, as the following example shows. template<typename Container, typename ValueType, int nPropType>
class property {}
This Template class will represent our property. The Container is the type of the class that will contain the variable, the set & get methods and the property. ValueType is the type of the internal variable itself. nPropType is the access type of the property (read only, write only or read write).
So now we need to set a pointer to the set and get method from the container class to the property and also override the operator = so that the property will act like the variable, so let's see the full listing of the property class. #define READ_ONLY 1
#define WRITE_ONLY 2
#define READ_WRITE 3
template <typename Container, typename ValueType, int nPropType>
class property
{
public:
property()
{
m_cObject = NULL;
Set = NULL;
Get = NULL;
}
void setContainer(Container* cObject)
{
m_cObject = cObject;
}
void setter(void (Container::*pSet)(ValueType value))
{
if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE))
Set = pSet;
else
Set = NULL;
}
void getter(ValueType (Container::*pGet)())
{
if((nPropType == READ_ONLY) || (nPropType == READ_WRITE))
Get = pGet;
else
Get = NULL;
}
ValueType operator =(const ValueType& value)
{
assert(m_cObject != NULL);
assert(Set != NULL);
(m_cObject->*Set)(value);
return value;
}
operator ValueType()
{
assert(m_cObject != NULL);
assert(Get != NULL);
return (m_cObject->*Get)();
}
private:
Container* m_cObject;
void (Container::*Set)(ValueType value);
ValueType (Container::*Get)();};
So now let's examine each piece.
The following code just sets the Container pointer to a valid instance that contains the property we're going to access. void setContainer(Container* cObject)
{
m_cObject = cObject;
}
The following code sets a pointer to the get and set member functions of the container class. The only restrictions are that the set member function must take a single parameter and return void and the get member function must take no parameters but return the value type.
void setter(void (Container::*pSet)(ValueType value))
{
if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE))
Set = pSet;
else
Set = NULL;
}
void getter(ValueType (Container::*pGet)())
{
if((nPropType == READ_ONLY) || (nPropType == READ_WRITE))
Get = pGet;
else
Get = NULL;
}
The first operator in the following code is the = operator, which calls the set member of the container passing the value. The second operator makes the entire property class act as the ValueType so it returns the value returned by the get function.
ValueType operator =(const ValueType& value)
{
assert(m_cObject != NULL);
assert(Set != NULL);
(m_cObject->*Set)(value);
return value;
}
operator ValueType()
{
assert(m_cObject != NULL);
assert(Get != NULL);
return (m_cObject->*Get)();
}
Now let's see how to use it.
As shown below, the PropTest class implements a simple property called Count. The actual value will be stored and retrieved from the private member variable m_nCount, through the get and set methods. The get and set methods can have any name as long as their addresses are passed to the property class as shown in the constructor of the PropTest object. The line property<PropTest,int,READ_WRITE> Count; says that we have a read & write property of type integer in class PropTest called Count. Now you can call Count as normal member variable even though you're really calling the set and get methods indirectly.
The initialization shown in the constructor of the PropTest class is necessary for the property class to work. class PropTest
{
public:
PropTest()
{
Count.setContainer(this);
Count.setter(&PropTest::setCount);
Count.getter(&PropTest::getCount);
}
int getCount()
{
return m_nCount;
}
void setCount(int nCount)
{
m_nCount = nCount;
}
property<PropTest,int,READ_WRITE> Count;
private:
int m_nCount;
};
As shown below you use the Count property as though it were a normal variable. int i = 5,
j;
PropTest test;
test.Count = i;
j = test.Count;
For read only properties you create an instance of the property as follows property<PropTest,int,READ_ONLY > Count;
And for write only properties you would create an instance of the property as follows property<PropTest,int,WRITE_ONLY > Count;
Note: If you set the property to read only and you try to assign to it, it will cause an assertion in debug builds. Similarly, if you set the property to write only and you try to read it an assertion will occur in debug builds.
Conclusion:
This shows how to implement properties in C++ using standard C++ without any extensions. Naturally, using set and get methods are more efficient because with this method you have a new instance of the property class per each property.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 50 (Total in Forum: 50) (Refresh) | FirstPrevNext |
|
|
 |
|
|
i am trying to make my own type of string class, but am not being able to overload << for cout and >> for cin. any help?
hari
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
#include #include #include #include #include using namespace std;
template class Property { private: T myVar; public: Property() { if ( PropertyType != 'r' && PropertyType != 'w' && PropertyType != 'b' ) { throw "Invalid PropertyType. PropertyTypes allowed are :: \n\tr ->Read , w -> Write , b -> Both Read and Write."; } } operator T() { return GetValue(); } void operator = ( T theVar ) { SetValue(theVar); } virtual T GetValue() { if ( PropertyType == 'w' ) { throw "Cannot read from a write-only property"; } return myVar; } virtual void SetValue(T theVar) { if ( PropertyType == 'r' ) { throw "Cannot write to a read-only property"; } myVar = theVar; } }; int _tmain(int argc, _TCHAR* argv[]) { try { Property aStringProperty; aStringProperty = "Anand"; string aStrProp = aStringProperty; cout << "Previosly assigned :: " << "Anand " << "Retrived from property :: " << aStrProp;
Property , 'b'> aVectorProperty; vector aVector; aVector.push_back(1);aVector.push_back(2);aVector.push_back(3);aVector.push_back(4);aVector.push_back(5); aVectorProperty = aVector; vector aNewVector = aVectorProperty; cout << "\n\nInitialised vector with values 1,2,3,4,5. Retrieving from vector property ::\n"; for ( int i = 0 ; i < 5 ; i++ ) { cout << aNewVector [ i ] << endl; } } catch( char* theException ) { cout << "\n\nException Occured : \n--------------------\n Message : " << theException ; } _getch(); return 0; }
Thanks and Regards, Anand.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Actual class definition is like template(typename T, char PropertyType) class Property
Also the read the include section as #include (tchar.h) #include (conio.h) #include (iostream) #include (string) #include (vector)
I dont know why the "less than symbol and greator than symbol" are dissappearing here ...so i used "(" for them....
Thanks and Regards, Anand.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Why so complicated?  Simpler is this:
//Visual C++ 7 class PropTest { public: PropTest(){}; int getCount() const {return m_nCount;} void setCount(int nCount){ m_nCount = nCount;} __declspec(property(get=getCount, put=setCount)) int Count;
private: int m_nCount; };
--- Mit freundlichen Grüßen -- Siegfried Bauer --
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
Did you read the first part of the article, I want to implement a portable property across compiler using standard C++ without any extension, __declspec is a MS VC extension, likewise there is C++Builder extension and manages C++ extension, but all these extension will work only on one compiler.
Regards, Emad
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
i think your property implementation can be improved in the following way so that your compiler helps you detect access errors to read_only or write_only properties:
enum EPropProperty { READ_ONLY = 0, WRITE_ONLY = 1, READ_WRITE = 2 };
template< unsigned int i > struct IntToType { enum { ret = i }; };
template< typename ValType, class Owner, EPropProperty Prop > class PropertyImpl;
template< typename ValType, class Owner > class PropertyImpl< ValType, Owner, READ_ONLY > { public: typedef ValType (Owner::*GetMethod)() const;
protected: void PutGetter( GetMethod pFnGet ) { m_pFnGet = pFnGet; }
GetMethod m_pFnGet; };
template< typename ValType, class Owner > class PropertyImpl< ValType, Owner, WRITE_ONLY > { public: typedef void (Owner::*SetMethod)( const ValType &rhs );
protected: void PutSetter( SetMethod pFnSet ) { m_pFnSet = pFnSet; }
SetMethod m_pFnSet; };
template< typename ValType, class Owner > class PropertyImpl< ValType, Owner, READ_WRITE > : public PropertyImpl< ValType, Owner, READ_ONLY > , public PropertyImpl< ValType, Owner, WRITE_ONLY > { };
template< typename ValType, class Owner, EPropProperty Prop > class Property : public PropertyImpl< ValType, Owner, Prop > { friend class Owner; public: typedef typename PropertyImpl< ValType, Owner, READ_ONLY >::GetMethod GetMethod; typedef typename PropertyImpl< ValType, Owner, WRITE_ONLY >::SetMethod SetMethod;
Property( Owner *const pThis ) : m_pThis( pThis ) {} Property( Owner *const pThis, GetMethod pFnGet ) : m_pThis( pThis ) { PropertyImpl< ValType, Owner, Prop >::PutGetter( pFnGet ); } Property( Owner *const pThis, SetMethod pFnSet ) : m_pThis( pThis ) { PropertyImpl< ValType, Owner, Prop >::PutSetter( pFnSet ); } Property( Owner *const pThis, GetMethod pFnGet, SetMethod pFnSet ) : m_pThis( pThis ) { PropertyImpl< ValType, Owner, Prop >::PutGetter( pFnGet ); PropertyImpl< ValType, Owner, Prop >::PutSetter( pFnSet ); } ~Property() {}
operator ValType() { return( GetValue( IntToType< Prop >() ) ); } void operator =( const ValType &rhs ) { SetValue( rhs, IntToType< Prop >() ); }
private: template< EPropProperty Prop > ValType GetValue( IntToType< Prop > );
template<> ValType GetValue( IntToType< READ_ONLY > ) { return( (m_pThis->*m_pFnGet)() ); } template<> ValType GetValue( IntToType< WRITE_ONLY > ) { class {} property_is_write_only[ 0 ]; } template<> ValType GetValue( IntToType< READ_WRITE > ) { return( (m_pThis->*m_pFnGet)() ); }
template< EPropProperty Prop > void SetValue( const ValType &rhs, IntToType< Prop > );
template<> void SetValue( const ValType &rhs, IntToType< READ_ONLY > ) { class {} property_is_read_only[ 0 ]; } template<> void SetValue( const ValType &rhs, IntToType< WRITE_ONLY > ) { (m_pThis->*m_pFnSet)( rhs ); } template<> void SetValue( const ValType &rhs, IntToType< READ_WRITE > ) { (m_pThis->*m_pFnSet)( rhs ); }
private: Owner* m_pThis; };
You can use it in the following way:
class A { public: A() : ReadOnlyProperty( this, A::GetReadOnlyProperty ) , WriteOnlyProperty( this, A::SetWriteOnlyProperty ) , AllAccessProperty( this, A::GetAllAccessProperty, A::SetAllAccessProperty ) , m_iReadOnlyProperty( 10 ) , m_dWriteOnlyProperty( 5.5 ) , m_cAllAccessProperty( 'A' ) { }
void AlternativeSetter( const char &c ) {}
Property< int, A, READ_ONLY > ReadOnlyProperty; Property< double, A, WRITE_ONLY > WriteOnlyProperty; Property< char, A, READ_WRITE > AllAccessProperty;
private: void SetWriteOnlyProperty( const double &val ) { m_dWriteOnlyProperty = val; }
int GetReadOnlyProperty() const { return( m_iReadOnlyProperty ); }
char GetAllAccessProperty() const { return( m_cAllAccessProperty ); } void SetAllAccessProperty( const char &val ) { m_cAllAccessProperty = val; }
private: int m_iReadOnlyProperty; double m_dWriteOnlyProperty;
char m_cAllAccessProperty; };
A a;
cout << a.ReadOnlyProperty << endl; // OK a.ReadOnlyProperty = 5; // results in a compiler error
cout << a.WriteOnlyProperty << endl; // results in a compiler error a.WriteOnlyProperty = 6.8; // OK
cout << a.AllAccessProperty << endl; // OK a.AllAccessProperty = 'B'; // OK
// a client cannot do something like this a.AllAccessProperty.PutSetter( A::AlternativeSetter );
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi I was trying to implement your version and i ran into tons of compiler problems. After i did some modifications, some of them went away but i can get past the following problem :
when it compiles the following : A() : ReadOnlyProperty( this, A::GetReadOnlyProperty ) , WriteOnlyProperty( this, A::SetWriteOnlyProperty ) , AllAccessProperty( this, A::GetAllAccessProperty, A::SetAllAccessProperty ) , m_iReadOnlyProperty( 10 ) , m_dWriteOnlyProperty( 5.5 ) , m_cAllAccessProperty( 'A' ) { }
__thiscall CProperty::CProperty(class A *const ,int (__thiscall Owner::*)(void) const)' : cannot convert parameter 2 from 'int (void) const' to 'int (__th iscall Owner::*)(void) const'
I wondered if you could give some advise on this ?
Thanks MASUD
Masud masud_masud@hotmail.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
In my project I need to clone classes. In that case it is easy if I can assign corresponding properties to one another. To do that, add the following code to the property class in the public section:
// Overload the '=' sign to enable assignments between properties property operator =(const property& value) { assert(m_Container != NULL); assert(Set != NULL); (m_Container->*Set)((value.m_Container->*value.Get)()); return *this; } friend property; // Somewhere in the class
Good stuff, the property class. I like simple, effective things that use standard C++ and/or stl.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
sorry about the length, buth all the operators are here. Note that there is no Postincrement or decrement operators included as they generated errors when used with classes such as strings
const unsigned READ_ONLY = 0x01; const unsigned WRITE_ONLY = 0x02; const unsigned READ_WRITE = 0x03;
template <typename container, typename T, unsigned type> class property { public: property(container* o = NULL): object(o), setter(NULL), getter(NULL) {} void SetContainer(container* o) { object = o; } void Setter(void (container::*set)(T v)) { assert(type & WRITE_ONLY); setter = set; }
void Getter(T (container::*get)()) { assert(type & READ_ONLY); getter = get; }
T operator =(const T& value) { assert((object != NULL) && (setter != NULL)); (object->*setter)(value); return value; }
operator T() { assert((object != NULL) && (getter != NULL)); return (object->*getter)(); } template <typename Type> T operator+(Type v2) { return (object->*getter)() + (T)v2; } template <typename Type> T operator-(Type v2) { return (object->*getter)() - (T)v2; } template <typename Type> T operator*(Type v2) { return (object->*getter)() * (T)v2; } template <typename Type> T operator/(Type v2) { return (object->*getter)() / (T)v2; } template <typename Type> T operator%(Type v2) { return (object->*getter)() % (T)v2; } template <typename Type> T operator^(Type v2) { return (object->*getter)() ^ (T)v2; } template <typename Type> T operator|(Type v2) { return (object->*getter)() | (T)v2; } template <typename Type> T operator&(Type v2) { return (object->*getter)() & (T)v2; } template <typename Type> T operator<< (Type v2) { return (object->*getter)() << (T)v2; } template <typename Type> T operator>> (Type v2) { return (object->*getter)() >> (T)v2; } template <typename Type> property operator+=(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() + (T)v); return *this; } template <typename Type> property operator-=(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() - (T)v); return *this; } template <typename Type> property operator*=(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() * (T)v); return *this; } template <typename Type> property operator/=(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() / (T)v); return *this; } template <typename Type> property operator%=(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() % (T)v); return *this; } template <typename Type> property operator^=(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() ^ (T)v); return *this; } template <typename Type> property operator|=(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() | (T)v); return *this; } template <typename Type> property operator&=(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() & (T)v); return *this; } template <typename Type> property operator<< =(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() << (T)v); return *this; } template <typename Type> property operator>> =(Type v) { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() >> (T)v); return *this; } const property &operator++() { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() + 1); return *this; } const property &operator--() { assert((object != NULL) && (setter != NULL) && (getter != NULL)); (object->*setter)((object->*getter)() - 1); return *this; } private: container* object; void (container::*setter)(T v); T (container::*getter)(); };
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello sir
gcc / mingw does not seem to compiel it, it reports at 'friend property;'
you may try it using devc++ which comes with mingw compiler.
Waiting for kind reply.
regards
easy GUI building www.radcpp.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
How about next MSVC attribute?
__declspec( property( get=get_func_name, put=put_func_name ) )
(seach a topic in MSDN by word 'property')
May be it's an easy way, than using templates?
Ken Keray
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
I know about the property of Visual C++, but the problem that Visual C++ property or Boland C++Builder property are extension to the C++ language, I want in this article to show how to implement a portable standard c++ property that can be compiled by any C++ compiler.
Regards, Emad
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
maybe you can tweak your code so it takes advantage of the __declspec(property) when _MSC_VER is defined?
I like the idea of properties - but the overhead of the container reference has always kept me away from it.
Just an idea
"Der Geist des Kriegers ist erwacht / Ich hab die Macht" StS
sighist | Agile Programming | doxygen
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
My own implementation (a bit of template madness) that I wrote this evening, takes care of operators, and you'll get compile time errors if you are trying to write to a read-only property. Compiles with VC.NET 2002. Example code at bottom, well commented as always. 
// // (C) Copyright Anders Dalvander 2003. // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. //
class property_void {};
template <typename owner_type_, typename value_type_> class getter;
template <typename owner_type_, typename value_type_> class setter;
template <typename owner_type_, typename value_type_, typename property1_type_, typename property2_type_ = property_void> class property;
template <typename owner_type_, typename value_type_> class property_base { public: typedef owner_type_ owner_type; typedef value_type_ value_type; typedef getter<owner_type, value_type> getter_type; typedef setter<owner_type, value_type> setter_type; typedef property<owner_type, value_type, getter_type, setter_type> readwrite_property_type; typedef property<owner_type, value_type, getter_type> readonly_property_type; typedef property<owner_type, value_type, setter_type> writeonly_property_type;
friend getter_type; friend setter_type;
property_base(owner_type* owner_) : owner(owner_) { }
private: owner_type* owner; };
template <typename owner_type_, typename value_type_> class getter { public: typedef owner_type_ owner_type; typedef value_type_ value_type; typedef value_type (owner_type_::*getter_func_type)() const; typedef property_base<owner_type, value_type> property_base_type;
getter(property_base_type* property_base_, getter_func_type getter_func_) : property_base(property_base_), getter_func(getter_func_) { }
value_type get_value() const { return (*property_base->owner.*getter_func)(); }
private: property_base_type* property_base; getter_func_type getter_func; };
template <typename owner_type_, typename value_type_> class setter { public: typedef owner_type_ owner_type; typedef value_type_ value_type; typedef void (owner_type_::*setter_func_type)(value_type); typedef property_base<owner_type, value_type> property_base_type;
setter(property_base_type* property_base_, setter_func_type setter_func_) : property_base(property_base_), setter_func(setter_func_) { }
void set_value(const value_type& rhs) { (*property_base->owner.*setter_func)(rhs); }
private: property_base_type* property_base; setter_func_type setter_func; };
template <typename owner_type_, typename value_type_, typename property1_type_, typename property2_type_ = property_void> class property : public property_base<owner_type_, value_type_>, private property1_type_, private property2_type_ { public: typedef owner_type_ owner_type; typedef value_type_ value_type; typedef property1_type_ property1_type; typedef property2_type_ property2_type; typedef property_base<owner_type, value_type> property_base_type; typedef property<owner_type, value_type, property1_type, property2_type> this_type;
property(owner_type* owner_, property1_type property1_) : property_base_type(owner_), property1_type(property1_) { }
property(owner_type* owner_, property1_type property1_, property2_type property2_) : property_base_type(owner_), property1_type(property1_), property2_type(property2_) { }
const value_type& operator=(const value_type& rhs) { set_value(rhs); return rhs; }
operator value_type() { return get_value(); }
value_type operator++() { set_value(get_value() + 1); return get_value(); }
value_type operator++(int) { const value_type value = get_value(); set_value(value + 1); return value; }
value_type operator--() { set_value(get_value() - 1); return get_value(); }
value_type operator--(int) { const value_type value = get_value(); set_value(value + 1); return value; }
template <typename rhs_type> value_type operator+=(const rhs_type& rhs) { set_value(get_value() + rhs); return get_value(); }
template <typename rhs_type> value_type operator-=(const rhs_type& rhs) { set_value(get_value() - rhs); return get_value(); }
template <typename rhs_type> value_type operator*=(const rhs_type& rhs) { set_value(get_value() * rhs); return get_value(); }
template <typename rhs_type> value_type operator/=(const rhs_type& rhs) { set_value(get_value() / rhs); return get_value(); }
template <typename rhs_type> value_type operator%=(const rhs_type& rhs) { set_value(get_value() % rhs); return get_value(); }
template <typename rhs_type> value_type operator<<=(const rhs_type& rhs) { set_value(get_value() << rhs); return get_value(); }
template <typename rhs_type> value_type operator>>=(const rhs_type& rhs) { set_value(get_value() >> rhs); return get_value(); }
template <typename rhs_type> value_type operator^=(const rhs_type& rhs) { set_value(get_value() ^ rhs); return get_value(); }
template <typename rhs_type> value_type operator&=(const rhs_type& rhs) { set_value(get_value() & rhs); return get_value(); }
template <typename rhs_type> value_type operator|=(const rhs_type& rhs) { set_value(get_value() | rhs); return get_value(); }
private: property(const this_type& rhs); const this_type& operator=(const this_type& rhs); };
// // Begin example code //
#include <iostream>
class foo { typedef property_base<foo, int> count_property_base_type; typedef count_property_base_type::readwrite_property_type count_property_type; typedef count_property_type::getter_type count_getter_type; typedef count_property_type::setter_type count_setter_type;
typedef property_base<foo, int> bar_property_base_type; typedef bar_property_base_type::readonly_property_type bar_property_type; typedef bar_property_type::getter_type bar_getter_type;
public: foo() : Count(this, count_getter_type(&Count, &foo::get_count), count_setter_type(&Count, &foo::set_count)), Bar(this, bar_getter_type(&Bar, &foo::get_bar)), count(0), bar(47) { }
int get_count() const { return count; } void set_count(int count_) { count = count_; }
int get_bar() const { return bar; }
count_property_type Count; // Read-write property. bar_property_type Bar; // Read-only property.
private: int count; int bar; };
int main() { foo foo; foo.Count = 13; std::cout << "(foo.Count) = " << (foo.Count) << std::endl; std::cout << "(foo.Count++) = " << (foo.Count++) << std::endl; std::cout << "(++foo.Count) = " << (++foo.Count) << std::endl; std::cout << "(foo.Count %= 10) = " << (foo.Count %= 10) << std::endl; //foo.Bar = 31; // Compile error if uncommented. std::cout << "(foo.Bar) = " << foo.Bar << std::endl; } Output:
(foo.Count) = 13 (foo.Count++) = 13 (++foo.Count) = 15 (foo.Count %= 10) = 5 (foo.Bar) = 47
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
You mean a property for an array of values? That's a bit different and the code will need some changing. One way of doing it would be to create a new property_array class that holds and array of properties to values, but that solution could be a bit bloaty if done incorrectly.
// Dalle
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I was thinking that the template would be simpler if it just owned the value. Also, the container class would not need to have a getter and setter. What do you think of an approach like this:
const unsigned property_readOnly = 0x01; const unsigned property_writeOnly = 0x02; const unsigned property_readWrite = 0x03;
template <typename ValueType, unsigned permissions> class property { public: property( ValueType initialValue ) : m_value(initialValue), m_permissions(permissions) { }
ValueType operator =(const ValueType& value) { assert( permissions & property_writeOnly ); m_value = value; return value; }
operator ValueType() { assert( permissions & property_readOnly ); return m_value; }
private: const unsigned m_permissions; ValueType m_value; };
class PropTest { public: PropTest() : Count(0) {} property<int,property_readWrite> Count; }
(I apologize if the code doesn't compile -- I don't have a compiler handy and I am not experience with templates.)
(As in the article, I've just asserted for permission violations. In real code I would prefer using mechanisms so that permission violations would not compile.)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Using this template property of yours is as good as making the variable public as everyone will have the same access to it. The getter and setter are the whole point, ok not the whole point but much of it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
| | |