7

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!

robdodson
  • 6,616
  • 5
  • 28
  • 35
  • There simply currently isn't a way to define getters/setters for accessing data members without making your own function like "GetVariable". – slartibartfast Dec 06 '11 at 01:59
  • Please pick up a [good book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) on C++. Well-designed classes don't usually have naive getters and setters. – Kerrek SB Dec 06 '11 at 01:59
  • ¤ As I (personally) see it, "properties" are generally abominations, buying a marginal notational convenience in return for giving up knowledge of what is a function call with possible side effects, and what is not. However, given that you want this you're probably not convinced merely by my opinion. ;-) So, to implement property `alpha`, just add a public member variable `alpha` that has an internal pointer to the containing object (to facilitate those interesting side effects) and that offers an assignment operator `operator=` and a type conversion operator `operator T`. Cheers & hth., – Cheers and hth. - Alf Dec 06 '11 at 02:03
  • Some dialects of C++ (notably Microsoft's) support properties natively. The code will be severely unportable though. – Seva Alekseyev Dec 06 '11 at 03:28

9 Answers9

6

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) { }
}
Daniel
  • 30,896
  • 18
  • 85
  • 139
  • Any reference material? It's kind of like an answer without an answer... lol I'd like to see any material on how this can be done. Do you know of any boost library that does this or makes it easier? –  Dec 10 '11 at 18:01
  • @AscensionSystems: all you have to do is make a class with overridden assignment and conversion operators. I don't know of any boost library that makes this easier. if you need this, I can add an example. – Daniel Dec 10 '11 at 18:05
  • Sure an example would be great, I'm pretty nooby and overloading any operators is territory I have yet to venture into. –  Dec 10 '11 at 18:30
5

"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.

tenfour
  • 36,141
  • 15
  • 83
  • 142
4

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.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • 1
    +1 for nice in-short elaboration of this scheme (my answer-as-comment was perhaps too short), and noting its general ungoodness. however, "have `member_t` aggregate pointers to these functions as members" is not necessary; a single pointer to the containing object generally suffices. i.e. there is inefficiency yes, but not *that* kind of glaring inefficiency. so i would have liked to upvote just 0.75, but not possible. :-) – Cheers and hth. - Alf Dec 06 '11 at 02:14
  • @AlfP.Steinbach: Could `member_t` be a reusable template if it only aggregated one pointer? Am I missing something obvious? – Jon Dec 06 '11 at 02:21
  • yes, and yes. :-) I think there must be many ways to do it, but I would make an id-type part of the template parameters. Then for property `alpha` of "logical" type `T`, I'd specify the data member type as `Property< T, struct alpha_IdType >`. Then the containing object's class *can* have a getter and a setter (or only the former) identifiable via the incomplete on-the-fly generated `alpha_IdType`, perhaps implementing an interface. This idea of identifying things via types can be pretty enabling. E.g. it forms the basis of the Boost Parameters library. Cheers, – Cheers and hth. - Alf Dec 06 '11 at 03:16
  • @AlfP.Steinbach What book(website?) should I pick to understand what you both are talking about? – Roman Byshko Dec 06 '11 at 03:32
  • 1
    @Beginner: to learn template programming stuff, I guess Andrei Alexandrescu's Modern C++ Design. It's very readable and clear. Cheers, – Cheers and hth. - Alf Dec 06 '11 at 05:24
  • The information in this answer helped me a lot. @Jon _"All of the above is certainly doable, but why would you want to write all this code? There is no tangible benefit at all"_. Sometimes you want to [port your library from Javascript to C++](http://kripken.github.io/emscripten-site/) and preserve property-like access to members in the process, so that users of your library don't have to change all of their code. – mucaho Aug 22 '15 at 15:19
2

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.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
  • 1
    In the end, if you're not doing any data massaging in a getter/setter, this is certainly the way to go for (a) clarity and (b) speed. – Mike Caron Feb 01 '12 at 20:14
1

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).

littleadv
  • 20,100
  • 2
  • 36
  • 50
1

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

TJD
  • 11,800
  • 1
  • 26
  • 34
  • 4
    It's no worse than having straight getters and setters for that variable, though. – Kerrek SB Dec 06 '11 at 02:00
  • 4
    It gives you the flexibility to later do fancier things in the getter/setter without a user of the class being aware. – TJD Dec 06 '11 at 02:01
1

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.

Jeremy
  • 824
  • 1
  • 9
  • 21
0

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)

AngeloDM
  • 397
  • 1
  • 8
0

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.

Mathieu Rodic
  • 6,637
  • 2
  • 43
  • 49
Chris Zheng
  • 1,509
  • 1
  • 15
  • 20