ansiart
ansiart

Reputation: 2591

Why am I disallowed from calling methods on an object I've returned by const reference?

This is a follow up question to my earlier question concerning returning references in C++: Best way to return an object in c++?

I can successfully return a reference, however, I am unable to prevent an observer to completely overwrite the variable in question. I have used const references, but I want an observer to be able to alter values.

Code below:

class Layer {
public:
    Channel&        getChannel();
private:
    Channel         channel;
};

// return reference to channel
Channel& Layer::getChannel() {
    return channel;
};

// FINE
layer.getChannel().someMethod();

// BAD: PRIVATE MEMBER IS OVERWRITTEN
layer.getChannel() = Channel();

Now I'm pretty sure to prevent this I have to alter the signature of the function to return a const reference, however, I'm unable to call someMethod afterwards:

// CHANGE TO CONST REFERENCE
Channel const& Layer::getChannel() {
    return channel;
};

// return const ref of channel
Channel const& channel = layer.getChannel();

// ERROR!!
// 'Channel::someMethod' : cannot convert 'this' pointer from 'const Channel' to 'Channel &'
channel.someMethod();

What's the correct way to write this — and is there a way to prevent overwriting of a private variable?

Upvotes: 0

Views: 99

Answers (3)

Ben Jackson
Ben Jackson

Reputation: 93930

[I agree with some of the other redesign solutions, but to answer the specific question]

If you want to return a mutable object but disallow assignment, make a private copy constructor and assignment operator on Channel. If you still need channel = ... elsewhere (which you may not if you use another explicit constructor in Layer) you can make Layer a friend.

Upvotes: 1

fredoverflow
fredoverflow

Reputation: 263360

Mark all methods that should be callable on const objects as const:

class Layer
{
    // ...

public:

    void someMethod() const;
};

void Layer::someMethod() const
{
    // ...
}

Note that you cannot mutate the object inside a const method, except for data members declared as mutable (which are quite rare; lazily initialized hash values come to mind).

If you want to prevent assignments, simply declare the assignment operator as private:

class Layer
{
    // ...

private:

    Layer& operator=(const Layer&);
};

Upvotes: 5

Benjamin Lindley
Benjamin Lindley

Reputation: 103761

If the object is private, users of the class should not know the object exists, or at least they should not need to know. You need to write public functions that perform the operations that you want the user to be able to perform.

So, instead of this:

layer.getChannel().someMethod();

You should have this:

layer.someOtherMethod();

Which calls a function that might look something like this:

X Layer::someOtherMethod()
{
    return channel.someMethod();
}

Upvotes: 1

Related Questions