简体   繁体   中英

dot property access in C++

I'm really new to C++ and one of the first things that has me really stumped is how to write a getter/setter that can use dot notation to get at a property.

For instance, instead of:

myObj.getAlpha();

it would be

myObj.alpha;

Is using dot notation like this frowned upon in C++ or is it just a pain to setup? I've had a hard time tracking down examples that weren't totally over my head so any guidance is much appreciated!

"Properties" in other programming languages are mostly a quick shorthand - a superficial shorthand for a pair of function calls. The other benefits (like metadata) don't really exist in C++. You have the following options:

  1. Make your own "properties". In other words, a getProperty() and setProperty() pair of functions.
  2. Expose a member variable as public. If you only want to expose a "getter", expose a public const reference to a member variable.
  3. As others are saying, write a class which you expose as a public member function, but handles the getting / setting so you can "intercept" it. This is, imo, way too much effort for whatever benefit it can provide.

I would suggest going with the simplest option for you, without giving up type safety & encapsulation. As long as the compiler still prevents external classes from messing things up in your class, public member variables are fine.

You can actually implement a getter and setter to a field like

myObj.alpha

but that is hard to setup and requires a proxy class.
The way for doing this is:

template<typename T>
class SetterProxy
{
    T *m_T;
  public:
    SetterProxy(T &property) : m_T(&property) { }
    SetterProxy(const SetterProxy&) = delete;
    SetterProxy operator =(const SetterProxy&) = delete;
    operator T&()
    {
        return *m_T;
    }
    T &operator =(T &other)
    {
        *m_T = other;
        return *m_T;
    }
}
class MyClass
{
    int m_alpha;
  public:
    SetterProxy<int> alpha;
    MyClass() : alpha(m_alpha) { }
}

Consider accessing the property using the proposed notation.

alpha is obviously a member of the class, let's say of type member_t . Let's also say that the property you intend to add is of type prop_t . Now if member_t is the same as prop_t you haven't really made a property because you have provided free access to the underlying member, so let's assume that member_t is different from prop_t .

It then follows that member_t must have an implicit conversion to prop_t (which is doable, but usually frowned upon).

It also means that member_t must override the assignment operator to store the value provided to it when you set it.

Finally, you have to add getter and setter methods to the class which implement the get/set logic, and have member_t aggregate pointers to these functions as members (so that it can call the getter inside the implicit conversion to prop_t and call the setter inside the overridden assignment operator).

All of the above is certainly doable, but why would you want to write all this code? There is no tangible benefit at all, and doing it just for the sake of making C++ look like a language it is not won't earn you much support.

The easiest way is to have alpha as just an accessible (probably public ) attribute of the class , or a variable !

class Obj
{
public:
    char alpha;

    Obj()
        :alpha('a')
    {
    }
};

int main()
{
    Obj myObj;
    char letter = myObj.alpha;
    // [...]
}

C++ doesn't have the "properties" that you are looking for.

If alpha is a public property of the class - you can do that. Nothing special to write for that, its built in.

You would use getters/setters for protected/private properties, because they're not directly accessible from outside (because, well, they're protected/private).

(by property I mean a class data member/variable, that's how its called in C++ usually).

You could declare your member variables public, then you don't need a function to access them. However this is normally not good practice.

Personally, I strongly agree with get\\set accessors - others may argue otherwise, and they are entitled to their own opinion.

With C++, there is no official way to create a property, however there are some compiler-specific methods that you can use to expose properties as you would in, for example, C#.

With Microsoft Visual C++, you can use the properties as is described here: http://msdn.microsoft.com/en-us/library/yhfk0thd%28v=vs.80%29.aspx and I'm sure there are other methods of performing the same task on other compilers. Most of my code is written on and for the windows platform so I can exercise this luxury, if you are planning on working with a different compiler, you should avoid using this for obvious reasons.

There may be some sort of BOOST implementation that allows you to do it more safely, but don't quote me on that. - I know boost can do some pretty cool things though.

As to why people use getters and setters, well. To start, directly accessing an object's data sounds messy, but it also removes a lot of flexibility.

Consider with get\\set accessors you can:

-More easily detect what is accessing your objects data

-Implement 'virtual variables' or rather, variables that contain data that must be generated per call.

-Redesign your object and possibly remove\\redesign variables without having to worry about backwards compatibility

-Override the get\\set accessors or implement them form an inherited interface.

I'm probably missing a couple reasons as well.

I posted on the my Italian blog a post where I explain a way to emulate the property construct of the CBuilder in the C++ standard. Just as reference here I report a class declaration called CPanel using the CBuilder syntax for property definition:

class CPanel
{
private:
  int m_Width;  // Private member for Width property
  int m_Height; // Private member for Height property

protected:
  void __fastcall SetWidth(int AValue); // Set the Width property
  int __fastcall GetWidth();            // Get the Width property

  void __fastcall SetHeight(int AValue);// Set the Height property
  int  __fastcall GetHeight();          // Get the Height property

public:
  CPanel()
  {
  }
  __property int Width  = {read=GetWidth,  write=SetWidth};
  __property int Height = {read=GetHeight, write=SetHeight};
}

As you see the the syntax is very simple, you can define the private members m_Height and m_Width, the protected setter and getter methods and finally you can define your properties using the special keyword called __property. The following code shows you how to use the properties in your main function:

int main()
{
    CPanel Panel;
    Panel.Width   = 10;
    Panel.Height  = 10;
    int TmpWidth  = Panel.Width;
    int TmpHeight = Panel.Height;
}

We can emulate the same syntax defining a template class for our generic property, the following code shows a definition of a template class for this purpose:

template<typename owner_t,
         typename prop_t,
         void (owner_t::*setter)(prop_t),
         prop_t (owner_t::*getter)()>
class CProperty
{
public:
  // Constructor
  CProperty(owner_t* owner){m_owner = owner;}

  // op = overloading
  void operator=(prop_t value)
  {   
    return (m_owner->*setter)(value);
  }
  // op type overloading
  operator prop_t()
  {   
    return (m_owner->*getter)();
  }
private:
  prop_t* m_owner;
}

Thanks the above template we can redefine our CPanel class using the standard c++ language:

class CPanel
{
private:
  int m_Width;  // Private member for Width property
  int m_Height; // Private member for Height property

protected:
  void SetWidth(int AValue); // Set the Width property  
  int  GetWidth();           // Get the Width property

  void SetHeight(int AValue);// Set the Height property
  int  GetHeight();          // Get the Height property

public:
  CPanel()
  :Width(this), Height(this)
  {
  }

  CProperty<CPanel, int, SetWidth,  GetWidth>  Width;
  CProperty<CPanel, int, SetHeight, GetHeight> Height;
}

As you can see the syntax is very similar, but now it is standard. You can use the new CPanel class like previous main function:

int main()
{
    CPanel Panel;
    Panel.Width   = 10;
    Panel.Height  = 10;
    int TmpWidth  = Panel.Width;
    int TmpHeight = Panel.Height;
}

Here is a link to the full post (in Italian language)

I believe you are coming from objective C?

In C++, getters and setters are just methods, and functions invokation always requires () .

You can make the property public, and use myObj.alpha to access it, although what you want is direct access, not a getter method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM