0

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?

Community
  • 1
  • 1
ansiart
  • 2,563
  • 2
  • 23
  • 41
  • 2
    How (or why) are you distinguishing "overwrite the variable in question" and "alter values"? Aren't they just the same thing - or at least part of the same spectrum of operations? What exactly do you want to prevent, or altenatively what exactly do you need to allow? – CB Bailey Apr 25 '11 at 17:26
  • Your goals are contradictory. If you allow the observer to call non-const operations on the object, and you have a public `operator=`, then the observer can call it just like any other operation. – Ben Voigt Apr 25 '11 at 17:27
  • I'm just trying to prevent this: layer.getChannel() = Channel(); – ansiart Apr 25 '11 at 17:32
  • I should note that all I'm trying to do, is protect a private object, but not copy the object (&getChannel()). – ansiart Apr 25 '11 at 17:34
  • See the second half of my answer, it explains how to disallow the assignment. – fredoverflow Apr 25 '11 at 17:36

3 Answers3

5

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&);
};
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
1

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();
}
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
1

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

Ben Jackson
  • 90,079
  • 9
  • 98
  • 150