Consider the following pattern:
class Child
{
public:
char Foo;
Child(char foo)
{
Foo = foo;
}
};
class Parent
{
public:
Child c;
Parent() : c('A') { }
const Child& GetChild() const
{
return c;
}
};
// Scenario 1: Works, but useless
int main()
{
Parent p = Parent();
Child c = p.GetChild();
c.Foo = 'B';
cout << p.c.Foo << endl; // A, wrong
cout << c.Foo << endl; // B, good
system("PAUSE");
}
// Scenario 2: Doesn't compile, of course
int main()
{
Parent p = Parent();
Child& c = p.GetChild(); // Error
c.Foo = 'B';
cout << p.c.Foo << endl; // A, good
cout << c.Foo << endl; // B, good
system("PAUSE");
}
The specification is the following:
- The getter must be defined as const (because it doesn’t modify Parent)
- The reference given by the getter must modify the underlying value
The problem is that:
- C++ requires the return value of the getter to be const if the getter itself is const (why?)
- C++ forbids assigning a const value to a reference (logically)
It is very easy to accomplish this using pointers (make the accessor return Child*), but there seems to be a consensus (and rightfully so) that references are advisable, considering they hide the complexity of pointers.
Is there any way to do it? If not, I’ll just revert to pointers.
If the returned reference wouldn’t be const, the caller could modify the object even if it was const in its own context:
However, this is only the problem when you are trying to return a member variable which is part of the class itself (which itself is not a pointer). So as you already suggested, making the Child a pointer would be OK. But returning a non-const pointer to a non-pointer
Childwould result in the same problem…To illustrate the problem better, consider this memory layout illustration:
So a parent contains a
Childobject and no more, so modifying yourParentinstance modifies aChildinstance, while modifyingParent::cmodifiesParentitself.So you can’t return a pointer or a reference to a non-const object (which the
thispointer points at in a const member function):Would be equal to:
where
thisis of typeconst Parent *, which means thatthis->cis of typeconst Child &. ReturningChild &violates the const-ness.The getter itself doesn’t modify the object, but it allows to circumvent the const-ness within the caller’s code, as seen in the code above.