CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    May 2013
    Posts
    18

    Creating a Property (Get/Set) Class

    Hi there,

    I've just recently moved from Visual Basic 6 over to C++ and decided that I would try and write a class to mimic the Get/Set behavior seen in a variety of other programming languages. So instead of just using an overloaded function, i.e:
    Code:
    class NoProp
    {
        LPCWSTR m_Title;
    public:
        void Title(LPCWSTR NewValue) {m_Title = NewValue;};
        LPCWSTR Title() {return m_Title;};
    };
    
    // ...
    
    instNoProp->Title(L"New title!");  // Set
    
    MessageBox(NULL, instNoProp->Title(), NULL, 0);  // Get
    I could just write the following:
    Code:
    instProp->Title = L"New title!";  // Set
    
    MessageBox(NULL, instProp->Title, NULL, 0);  // Get
    After about a week of playing around I came up with the following Property class, and another class named InitProp as a helper.
    Code:
    #include <windows.h>
    
    template <class tParent, class tProperty>class Property;
    
    template <class tParent, class tProperty>
    class InitProp
    {
    	typedef tProperty (tParent::*GET_PROP)(tParent*);
    	typedef void (tParent::*SET_PROP)(tParent*, tProperty);
    
    public:
    	InitProp(tParent *cParent,
    			 Property<tParent, tProperty> *cProperty,
    			 tProperty *&tVariable,
    			 GET_PROP Get_Property,
    			 SET_PROP Set_Property)
    	{
    		cProperty->m_Property = new tProperty;
    		*cProperty->m_Property = NULL;
    
    		tVariable = cProperty->m_Property;
    
    		cProperty->m_Parent = cParent;
    		cProperty->m_Copy = 0;
    		cProperty->m_Get_Property = Get_Property;
    		cProperty->m_Set_Property = Set_Property;
    	};
    };
    
    template <class tParent, class tProperty>
    class Property
    {
    	typedef tProperty (tParent::*GET_PROP)(tParent*);
    	typedef void (tParent::*SET_PROP)(tParent*, tProperty);
    
    public:
    	friend class InitProp<tParent, tProperty>;
    
    	Property()
    	{
    		m_Parent = NULL;
    		m_Set_Property = NULL;
    		m_Get_Property = NULL;
    	};
    
    	~Property()
    	{
    		if (m_Copy-- == 0)
    			delete m_Property;
    	};
    
    	Property operator= (tProperty NewValue)
    	{
    		if (m_Set_Property != NULL)
    			(m_Parent->*m_Set_Property)(m_Parent, NewValue);
    		
    		return *this;
    	}
    
    	Property(const Property& Prop)
    	{
    		++m_Copy;
    	};
    
    	operator tProperty()
    	{
    		if (m_Get_Property != NULL)
    			return (m_Parent->*m_Get_Property)(m_Parent);
    		else
    			return NULL;
    	};
    
    private:
    	int m_Copy;
    	tParent *m_Parent;
    	tProperty *m_Property;
    	GET_PROP m_Get_Property;
    	SET_PROP m_Set_Property;
    };
    
    class Form
    {
    public:
    	Property<Form, LPCWSTR> Title;
    
    	Form()
    	{
    		InitProp<Form, LPCWSTR> pTitle(this, &Title, m_Title, &Form::g_Title, &Form::s_Title);
    	};
    
    private:
    	LPCWSTR *m_Title;
    
    	LPCWSTR g_Title(Form *Sender)
    	{
    		// User called Form.Title
    
    		return *Sender->m_Title;
    	};
    
    	void s_Title(Form *Sender, LPCWSTR NewValue)
    	{
    		// User set Form.Title =
    
    		*Sender->m_Title = NewValue;
    	};
    
    };
    
    int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    	Form *frmMain;
    	frmMain = new Form;
    
    	frmMain->Title = L"This is just a test!";
    
    	MessageBox(NULL, frmMain->Title, NULL, 0);
    
    	delete frmMain;
    
    	return 0;
    }
    So far this code only works with the LPCWSTR type (const wchar_t*). Unfortunately I got to this stage using only that type, and now when I try another type, such as int, it fails. When using the int type I believe it creates an error because the constructor of InitProp expects a type of pointer to be parsed. When I try using it with int* type (the private variable then becoming int **m_Variable) it compiles, thought I cannot access the property like a normal int.

    My best guess from here is that I probably have to overload the InitProp constructor in a way that it can setup the Property classes for base-types and pointer-types, and then also modify the Property class to handle both.

    I'd appreciate any suggestions and input as I'm becoming lost in template->pointer-land.

    Thanks!

  2. #2
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Creating a Property (Get/Set) Class

    Quote Originally Posted by FrOzeN89 View Post
    Hi there,

    I've just recently moved from Visual Basic 6 over to C++ and decided that I would try and write a class to mimic the Get/Set behavior seen in a variety of other programming languages. So instead of just using an overloaded function, i.e:
    Code:
    class NoProp
    {
        LPCWSTR m_Title;
    public:
        void Title(LPCWSTR NewValue) {m_Title = NewValue;};
        LPCWSTR Title() {return m_Title;};
    };
    
    // ...
    
    instNoProp->Title(L"New title!");  // Set
    
    MessageBox(NULL, instNoProp->Title(), NULL, 0);  // Get
    I could just write the following:
    Code:
    instProp->Title = L"New title!";  // Set
    
    MessageBox(NULL, instProp->Title, NULL, 0);  // Get
    Thanks!
    Why?
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  3. #3
    Join Date
    May 2013
    Posts
    18

    Re: Creating a Property (Get/Set) Class

    I thought controlling public class variables would be quite common. Maybe I'm just too used to VB6 syntax.

    Is the standard for this type of use just to use the regular function overload method, whilst having the variables private?

  4. #4
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Creating a Property (Get/Set) Class

    Quote Originally Posted by FrOzeN89 View Post
    Is the standard for this type of use just to use the regular function overload method, whilst having the variables private?
    That's the way it's usually implemented. Often without even using function overload ie. GetTitle() and SetTitle(..).
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  5. #5
    Join Date
    May 2009
    Posts
    2,413

    Re: Creating a Property (Get/Set) Class

    Quote Originally Posted by FrOzeN89 View Post
    I thought controlling public class variables would be quite common. Maybe I'm just too used to VB6 syntax.

    Is the standard for this type of use just to use the regular function overload method, whilst having the variables private?
    Neither C++ nor Java has any language features in support of the concept of Properties.

    Unfortunately, since Properties has associated getter/setter methods they've become collaterally damaged by another discussion, namely whether getters/setters are to be considered bad OO and therefore "evil".

    http://www.javaworld.com/javaworld/j...5-toolbox.html

    The implication here is that also Properties must be "evil" because they have getters/setters. I don't share this view. Properties makes sense and not overusing setters/getters also makes sense. They're separate discussions.

    Anyway in C++ and Java you supply getter/setter methods where you see them fit. But in C++ of course you can make some fuzz about it and develop a general Properties mechanism, as you are doing. This is what makes C++ superior to other languages. You can add features that extend it as a language.

    Developing a general scheme for Properties in C++ is quite involved and I don't have time for that. But good luck, and mere trying will make you a better C++ programmer . Finally, ordinary getter/setter methods will do fine and the are Properties if they are considered as such by design.
    Last edited by nuzzle; May 17th, 2013 at 04:58 PM.

  6. #6
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: Creating a Property (Get/Set) Class

    Quote Originally Posted by 2kaud View Post
    Why?
    Errr... Good question!

    I mainly took this as a funky experimental exercise and came to an alternative approach that uses operator overloading to mimic the original behaviour of the wrapped object to the outside world:

    Code:
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    template<class T> class primitive_property
    {
    public:
      primitive_property() : m_payload(T()) {}
      primitive_property(const T &init) : m_payload(init) {}
    
      virtual ~primitive_property() {}
    
      virtual const primitive_property &operator=(const primitive_property<T> &other)
      {
        m_payload = other.m_payload;
        return *this;
      }
    
      virtual const T &operator=(const T &newval)
      {
        m_payload = newval;
        return newval;
      }
    
      virtual operator T() const
      {
        return m_payload;
      }
    
    protected:
      T m_payload;
    };
    
    template<class T> class complex_property : public primitive_property<T>
    {
    public:
      template<class U> complex_property(const U &init) : primitive_property(T(init)) {}
    
      virtual T *operator->()
      {
        return &m_payload;
      }
    
      friend ostream &operator<<(ostream &ostrm, const complex_property<T> &rhs)
      {
        return ostrm << rhs.m_payload;
      }
    };
    
    class TestClass
    {
    public:
      TestClass() : prop_int(2), prop_charptr("default"), prop_string("default string") {}
    
    public:
      primitive_property<int> prop_int;
      primitive_property<char *> prop_charptr;
      complex_property<string> prop_string;
    };
    
    int main(int argc, char *argv[])
    {
      TestClass c;
      c.prop_int = 3;
      c.prop_charptr = "spectacular";
      c.prop_string = "spectacular string";
      cout << c.prop_int << ", " << c.prop_int + 2 << ", " << c.prop_int + c.prop_int << endl;
      cout << c.prop_charptr << ", " << *c.prop_charptr << ", " << c.prop_charptr[1] << endl;
      cout << c.prop_string << ", " << c.prop_string->length() << endl;
      return 0;
    }
    The primitive property class' operator T() is an implicit conversion of the property object to the wrapped object's type, so it can transparently be used like an object of the wrapped type in many situations. The conversion operator returns a copy of the wrapped value, so it can't be used to change the property. That's what the two (!) assignment operators are for, one that operates on the property class itself, as usual, and one that operates directly on the wrapped object, to circumvent creation of a temporary property object in the not so unlikely case of assigning an object of the wrapped type to the property.

    The primitive property class is just what the name suggests: Designed to be used with primitive types, including pointers. For the more advanced stuff there's the derived complex property class. It defines an operator->() overload that allows access to members of the wrapped object, much like smart pointer classes do.

    IMO properties are really cool compared to ordinary data members only if the getters/setters are able to do a bit more than just transparently transfer data between the underlying field and the outside world. Therefore, practically everything in the two classes is virtual, allowing to derive from them and extend/modify their default behaviour by some overrides. The complex property class' operator<<() is declared friend, thus effectively a free function, so it can't be overridden. This limitation can be overcome by introducing a virtual streaming function in the property class and then call that from the operator implementation.

    This mainly is just a quick hack and has a lot of shortcomings, and probably some bugs and design weaknesses. The classes, as they are now, wouldn't work with types that aren't assignable/copy constructable. Also, the complex property class wouldn't work with types that are not streamble. To make it half-way useful in practice, this "property framework" would need quite some more work, probably including some more generic property templates and a bunch of explicit template specializations.

    That said, I, personally, wouldn't further pursue this approach anyway. I don't think C++ really needs properties that syntactically mimic plain data members.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  7. #7
    Join Date
    May 2013
    Posts
    18

    Re: Creating a Property (Get/Set) Class

    Wow, thank you for all the input. I think I might stick to overloaded functions as I want to make my code relatively standard.

    The idea was so I could do things like Form.Width = 180, and it would call something like WindowSetPos API using the current x, y, and m_Height, but change m_Width to 180 and resize it.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured