Eugene
Eugene

Reputation: 598

Returning pointer on class member from const member function

Are these definitions of pointer() equal?

class Example
{
public:
    AnotherClass* const pointer() const;
    AnotherClass* pointer() const;


private:
    AnotherClass* m_pointer;
}

Does it guarantee me what somebody can't change m_pointer memory pointed to?

Upvotes: 0

Views: 161

Answers (3)

Cassio Neri
Cassio Neri

Reputation: 20503

There are a few things to consider here:

What is const: the pointer or the pointee?

Let's see the differences between these different declarations.

int x, y;

int       *       p = &x; // 0
const int *       p = &x; // 1
int const *       p = &x; // 2
int       * const p = &x; // 3
const int * const p = &x; // 4
int const * const p = &x; // 5

(0) means that p can change (p = &y; is OK) and what it points to (x) can be changed via p (*p = y; is OK).

(1) and (2) are equivalent and mean that p can change (p = &y; is OK) and what it points to (x) cannot be changed via p (*p = y; is an error).

(3) means that p cannot change (p = &y; is an error) and what it points to (x) can be changed via p (*p = y; is OK)

(4) and (5) are equivalent and mean that p cannot change (p = &y; is an error) and what it points to (x) cannot be changed via p (*p = y; is an error).

An easy way to remember this is looking at the * and think that it separates the objects constness, that is,

(a) a const before * (e.g. const int * [...] or int const * [...]) means the pointed object (of type int) is const; and

(b) a const after * (e.g. [...] * const p [...];) means that the pointer is const and cannot be changed.

What happens if a function returns a const object?

Consider:

class some_class;

const some_class a(); // equivalent to 'some_class const a();'
      someclass  b();

const int        c(); // equivalent to 'int const c();'
      int        d();

Then, (assuming some_class has an accessible assignment operator) we have:

some_class x;

a() = x; // illegal : the returned object is const
b() = x; // OK      : the returned object is not const

It's natural to believe that c() and d() behave the same but this is not the case:

c() = 0; // illegal
d() = 0; // also illegal!!!

The reason is that if a function returns a fundamental type (e.g. int, bool, char, any pointer type, ...) then the returned object cannot be assigned to. Therefore, returning a const object of fundamental type behaves the same as to returning a non-const one.

What about overloading on the return type?

Consider

int    f(); // first  overload.
double f(); // second overload.

This is illegal. We cannot overload on the return type only. One reason is that we can always ignore the object returned by a function. For instance, if overloading on the return type was allowed, then which overload of f would be called below?

int main() {
    f(); // which f?
    return 0;
}

Answering the question...

Consider the first declaration

AnotherClass* const pointer() const;

From what we have seen, this means that pointer() returns a const object of type AnotherClass* (a pointer type). Since a pointer type is a fundamental type, the function pointer above behaves the same as if it was declared as

AnotherClass* pointer() const;

which is the second overload. This is the first reason why having these two overloads doesn't make sense. But this is just a weak reason compared to the one that follows.

When I say "behaves the same" I don't mean "equivalent". The return type of the two overloads are different. As we have seen, we cannot overload on the return type only. This is illegal and the code doesn't compile.

Does it guarantee me what somebody can't change m_pointer memory pointed to?

No, again, both overloads behave the same and return a pointer to an object that can be changed via this pointer. What you want is this:

   const AnotherClass* pointer() const { return m_pointer; }
// or
// AnotherClass const* pointer() const { return m_pointer; }

Notice the const at the left of *.

Upvotes: 1

Werner Henze
Werner Henze

Reputation: 16726

The two overloads for pointer only differ in the return type. Your C++ compiler will not accept that, this is an error.

Assuming that pointer() just returns m_pointer:

The declaration AnotherClass* pointer() const; would expose the value of m_pointer. Users of the class would not be able to change m_pointer, but they could change the object that m_pointer points to.

The declaration AnotherClass* const pointer() const; is quite similar to AnotherClass* pointer() const; but the value returned (the temporary pointer) is const. This declaration does not really make sense because you already can't change the return value in the first declaration. You can't write example.pointer() = nullptr in either cases. And when you assign the return value to a variable like in p = example.pointer() it makes no difference if the return value of pointer() is const or not.

The declarations const AnotherClass* pointer() const; and AnotherClass const * pointer() const; would expose the value of m_pointer. Users of the class would not be able to change m_pointer, and they would not be able to change the object that m_pointer points to.

Upvotes: 1

Grimm The Opiner
Grimm The Opiner

Reputation: 1806

You need the return type for the first method to be one of these:

    AnotherClass const * pointer() const;

or

    const AnotherClass* pointer() const;

What you have done is return a const pointer to a non-const object.

What you want is a non-const pointer to a const object.

Also, to follow the typical practice your second method should not be const.

    AnotherClass* pointer();

Upvotes: 2

Related Questions