Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant solution to duplicate, const and non-const, getters? [duplicate]

Tags:

c++

constants

I recall from one of the Effective C++ books that the way to do it is to implement the non-const version by casting away the const from the other function.

It's not particularly pretty, but it is safe. Since the member function calling it is non-const, the object itself is non-const, and casting away the const is allowed.

class Foo
{
public:
    const int& get() const
    {
        //non-trivial work
        return foo;
    }

    int& get()
    {
        return const_cast<int&>(const_cast<const Foo*>(this)->get());
    }
};

How about:

template<typename IN, typename OUT>
OUT BigChunk(IN self, int index) {
    // big, non-trivial chunk of code...
    return something;
}

struct FooBar {
    Something &getSomething(int index) {
        return BigChunk<FooBar*, Something&>(this,index);
    }

    const Something &getSomething(int index) const {
        return BigChunk<const FooBar*, const Something&>(this,index);
    }
};

Obviously you'll still have object code duplication, but no source code duplication. Unlike the const_cast approach, the compiler will check your const-correctness for both versions of the method.

You probably need to declare the two interesting instantiations of BigChunk as friends of the class. This is a good use of friend, since the friend functions are hidden away close to the friendee, so there is no risk of unconstrained coupling (ooh-er!). But I will not attempt the syntax for doing so right now. Feel free to add.

Chances are that BigChunk needs to deference self, in which case the above order of definition isn't going to work very well, and some forward declarations will be needed to sort it out.

Also, in order to avoid some numpty finding BigChunk in the header and deciding to instantiate and call it even though it's morally private, you can move the whole lot into the cpp file for FooBar. In an anonymous namespace. With internal linkage. And a sign saying "beware of the leopard".


I would cast the const to the non-const (second option).


Try to eliminate the getters by refactoring your code. Use friend functions or classes if only a very small number of other things needs the Something.

In general, Getters and Setters break encapsulation because the data is exposed to the world. Using friend only exposes data to a select few, so gives better encapsulation.

Of course, this is not always possible so you may be stuck with the getters. At the very least, most or all of the "non-trivial chunk of code" should be in one or more private functions, called by both getters.


Why not just pull the common code out into a separate, private function, and then have the other two call that?


The const reference to the object makes sense (you're putting a restriction on read-only access to that object), but if you need to allow a non-const reference, you might as well make the member public.

I believe this is a la Scott Meyers (Efficient C++).