views:

1671

answers:

8

Hi,

I would like to know a good syntax for C++ getters and setters.

private:
YourClass *pMember;

the setter is easy I guess:

void Member(YourClass *value){
  this->pMember = value; // forget about deleting etc
}

and the getter? should I use references or const pointers?

example:

YourClass &Member(){
   return *this->pMember;
}

or

YourClass *Member() const{
  return this->member;
}

whats the difference between them?

Thanks,

Joe

EDIT:

sorry, I will edit my question... I know about references and pointers, I was asking about references and const pointers, as getters, what would be the difference between them in my code, like in hte future, what shoud I expect to lose if I go a way or another...

so I guess I will use const pointers instead of references

const pointers can't be delete or setted, right?

+5  A: 

As a general law:

  • If NULL is a valid parameter or return value, use pointers.
  • If NULL is NOT a valid parameter or return value, use references.

So if the setter should possibly be called with NULL, use a pointer as a parameter. Otherwise use a reference.

If it's valid to call the getter of a object containing a NULL pointer, it should return a pointer. If such a case is an illegal invariant, the return value should be a reference. The getter then should throw a exception, if the member variable is NULL.

RED SOFT ADAIR
how about: if null is not a valid parameter or return value, use return by value? (no pointers, no refs)
hasen j
That's way over simplified. But then again the question is way to generalized to answer correctly.
Martin York
I would use return by value only for built-ins, for the rest I'd rather avoid the cost of copy-construction. // for getters, of course if you need to compute something, then it's way different
Matthieu M.
+2  A: 

whats the difference between them?

The reference is an alias of the thing(it is the thing*). A pointer is the address of the thing. If there's a chance that what's pointed to won't be there, then you probably don't want to return references. References tell the caller "I'm going to give you an alias that will exist when I return it to you". In fact there's really no way to check the reference to see if what's underlying is valid.

With the pointer, semantically, you are implying that the caller may wish to check to see if Member exists before using it. Ussually this is done with a NULL check.

Ultimately there's no "right" answer. It depends on the class's contract and if the caller will/should/wants to check whether "Member" is still around.

The short answer is pointers for things that can be pointed elsewhere and references for "unseated" aliases.

Doug T.
sorry, I will edit my question... I know about references and pointers, I was asking about references and const pointers, as getters, what would be the difference between them in my code, like in hte future, what shoud I expect to lose if I go a way or another...
Jonathan
+3  A: 

The best thing is to provide a real OO interface to the client that hides implementaton details. Getters and Setters are not OO.

DevFred
I am, but I like getters and setters instead of public variables. I hardly use public variables, only when needed, or at least protected variables
Jonathan
I think what DevFred is suggesting is that you avoid both getters/setters AND public variables. Instead, try to define active methods that do the work for you.
Boojum
can you give me an example? I am creating abstract classes and deriving from them and most of my getters, setters and functions are virtual... I guess I didn't get what he meant
Jonathan
getters and setters are very Java/C# style (not C++). They are a result of these languages reliance on reflection and frameworks to build the object. Getters and Setter destroy the OO nature of a language and explicitly allow you to meddle in the internal structure of an object. This is frowned apon in C++ were it is more common to have the object fully formed after the constructor is complete.
Martin York
can you give me an example of this "active methods" etc? if I am not making the variables public and not creating getters or setters, then how should I use the class? O_o Sorry if this is kinda silly, but I really odn't get it :(
Jonathan
This probably deserves its own question, actually. But as a simple example, imagine you have a character in a game and you want to try moving north. You could call getX() and getY() to gets its position, add the right values to these, call the map object to see if that position is free, and the call setX() and setY() to update its position. If you have a move() method on the character, though, you've centralized that logic. You're now free to change how the character stores its position without going all over the code. And now both the AI and the player control can use that common method.
Boojum
+1  A: 

+1 on questioning the use of setters and getters. If you must use them and have the possibility of nulls consider using boost::shared_ptr. This way ownership is handled for you.

Ben
I wouldn't like to use boost yet, as I am learning, I would like to create this project with the less external libraries possible...
Jonathan
+3  A: 

As others have said, use pointers if null is a possibility.

In most cases, I prefer to use references when possible. Personally, in my code, I like to use the distinction between pointers and references to signal ownership. I think of calls with references as "loaning" an object to another function or class. The original class that passed or returned the reference still owns it, and is responsible for its creation, maintenance and clean up. When my code passes a non-const pointer, on the other hand, it usually means that there's some kind of transfer or sharing of ownership going on, with all the responsibilities that entails.

(And yes, I usually use smart pointers. Those are akin to references in my mind. I'm talking about lower level code than that here.)

Boojum
A: 

Jonathan, what compiler are you using? There's a great chance that shared_ptr already comes shipped with it as part of the compiler's TR1 implementation.

DevFred
+3  A: 

Your code looks a great deal as if you're accustomed to a different language -- in C++ using this->x (for one example) is relatively unusual. When the code is at all well written, so is using an accessor or mutator.

Though I'm fairly unusual in this particular respect, I'll go on record (yet again) as saying that forcing client code to use an accessor or mutator directly is a bad idea. If you honestly have a situation where it makes sense for client code to manipulate a value in your object, then the client code should use normal assignment to read and/or write that value.

When/if you need to control what value is assigned, operator overloading lets you take that control without forcing ugly get/set syntax on the client code. Specifically, what you want is a proxy class (or class template). Just for one example, one of the most common situations where people want get/set functions is something like a number that's supposed to be restricted to some particular range. The setXXX checks the new value for being in range, and the getXXX returns the value.

If you want that, a (fairly) simple template can do the job much more cleanly:

template <class T, class less=std::less<T> >
class bounded {
    const T lower_, upper_;
    T val_;

    bool check(T const &value) {
        return less()(value, lower_) || less()(upper_, value);
    }

    void assign(T const &value) {
        if (check(value))
            throw std::domain_error("Out of Range");
        val_ = value;
    }

public:
    bounded(T const &lower, T const &upper) 
        : lower_(lower), upper_(upper) {}

    bounded(bounded const &init) 
     : lower_(init.lower), upper_(init.upper)
    { 
     assign(init); 
    }

    bounded &operator=(T const &v) { assign(v);  return *this; }

    operator T() const { return val_; }

    friend std::istream &operator>>(std::istream &is, bounded &b) {
        T temp;
        is >> temp;

        if (b.check(temp))
            is.setstate(std::ios::failbit);
        else
            b.val_ = temp;
        return is;
    }
};

This also makes the code much closer to self documenting -- for example, when you declare an object like: bounded<int>(1, 1024);, it's immediately apparent that the intent is an integer in the range of 1 to 1024. The only part somebody might find open to question is whether 1 and/or 1024 is included in the range. This is considerably different from defining an int in the class, and expecting everybody who ever looks at the class to realize that they're supposed to use the setXXX to enforce some (at that point unknown) set of bounds on the values that can be assigned.

When you embed one of these in a class, you make it a public variable, and the range is still enforced. In the client code, there's no real argument over syntax -- you're just assigning to a public variable, like you would any other -- with the minor detail that attempting to assign a value that's out of range will throw an exception. In theory, the class should probably take a policy template-parameter to specify exactly what it does in that case, but I've never had a real reason to bother with that.

Jerry Coffin
sorry, but looking at that code makes a lot harder(at least for me) to understand than a getter or a setter. It is not easy for me to think that creating a templated class or just a class for a simple rule is better than a simple set function. Think of a large library that is going to be used by other libraries or executables, I think that overloading the assignment operator is not the best approach, Of course I am just a newbie, but from what I've been reading, assignment operator should only be overloaded when strcitly needed, like the Rule of Tree that Martin wrote in other thread of mine
Jonathan
If all you were ever going to write was one getter and one setter, you'd be right -- this code would be more complex. When you can replace dozens (potentially hundreds) of getters and setters with one template, however, it simplifies the code considerably. Regardless of that, it centralizes all the complexity. A getter and setter require *all* the code to be aware of the implementation and add complexity to deal with it. This puts all the complexity in one place, and simplifies all the other code.
Jerry Coffin
A: 

In addition to the other answers, if you choose references for the getter don't write it like in your example:

YourClass &Member(){
   return *this->pMember;
}

Your getter actually allows setting, as in instance->Member() = YourClass(); and thus bypassing your setter. This might not be allowed if YourClass is noncopyable, but is still another thing to have in mind. Another drawback is the getter is not const.

Instead, write your getter like this:

const YourClass &Member() const {
   return *this->pMember;
}
sbk