Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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

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.

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

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.

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;
}

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top