3

I've been learning C++ and I am practicing with classes at the moment. I created a class that stores a name and a score of a player and defines functions to manipulate the data and show it.

One of the functions I created is to compare scores of two players and return a pointer to the player with the higher score. This is the function:

Player * Player::highestScore(Player  p2)const
{
    if(p2.pScore>pScore)
    {
        return &p2;
    }
    else
    {
        return this;
    }
}

From the main I create the following players:

Player p1("James Gosling",11);
Player *p4 = new Player("Bjarne Stroustrup",5);

I call the highestScore function:

Player *highestScore = p1.highestScore(*p4);

However as you may have noticed from reading the function itself, when I return the pointer to the object that called the method (if it has a higher score), I get an error that says:

return value type does not match the function type

This problem seems to disappear when I declare the return type of the function as a const, like this:

const Player * Player::highestScore(Player  p2)const

The part that is confusing me is why does it allow me to return &p2, which is not const and doesn't allow me to return this, which is a pointer to the object that called the function, which isn't a const as well? Also even when I declare the function return type as a const, it still allows me to return &p2, even though the argument passed to the parameter is not a const Player object?

Sorry if the question seems strange or what I'm trying to do is very bad programming, but it's just for the purpose of learning by doing it.

Kakalokia
  • 3,191
  • 3
  • 24
  • 42
  • This previously answered question may help -- http://stackoverflow.com/questions/6919330/return-this-in-c – Kevin Mangold Feb 06 '13 at 16:07
  • 3
    `this` is const because the member function is declared as const. The parameter `p2` is *not* declared in the parameter list as `const` and therefore you *can* return its address, but note in doing so you're returning the address of a stack variable that was pushed by-val and is therefore undefined behavior if the address is ever referenced outside your member function. – WhozCraig Feb 06 '13 at 16:11
  • @WhozCraig: Right, he probably meant `const Player* Player::highestScore(Player& p2) const`, using a reference – Ben Voigt Feb 06 '13 at 16:12
  • 2
    @BenVoigt Agreed, but hard saying. The unfamiliarity with `const`'ness is a subtle hint that other attributes of the language (like returning the address of a temporary or the fact that `*p4` in his example is actually pushed by-val) may likewise not yet be in his purvey. – WhozCraig Feb 06 '13 at 16:14
  • @WhozCraig thanks that cleared some confusion. – Kakalokia Feb 06 '13 at 16:26

3 Answers3

7

The part that is confusing me is why does it allow me to return &p2, which is not const and doesn't allow me to return this, which is a pointer to the object that called the function, which isn't a const as well?

this is const (or, more accurately, is a pointer-to-const) in a const member function, just like all the data members:

#include <iostream>
#include <type_traits>

struct A
{
    void foo()
    {
        std::cout << std::is_same<decltype(this), const A*>::value << '\n';
    }

    void bar() const
    {
        std::cout << std::is_same<decltype(this), const A*>::value << '\n';
    }
};

int main()
{
    A a;
    a.foo();
    a.bar();
}

Output:

0
1

Also even when I declare the function return type as a const, it still allows me to return &p2, even though the argument passed to the parameter is not a const Player object?

We can't see what you tried, but presumably it was Player* const, which is not the same as Player const* (or const Player*). You can add constness to &r2 just fine; taking constness away is a different story.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Thanks for the answer. If you mean you can't see how I tried initializing the pointer of the p2 parameter from main, I did it in the following: Player *p4 = new Player("Bjarne Stroustrup",5); – Kakalokia Feb 06 '13 at 16:17
  • No, I meant that we didn't see your attempt at "declar[ing] the function return type as a const". But it doesn't matter. – Lightness Races in Orbit Feb 06 '13 at 16:19
3

The difference between a const and non-const method is that in the first the this pointer in const and in the latter it is not. So when you try to return non-const pointer from a const function and return this, compiler complains, because there this is const and const-ness can not be automatically removed.

&p2 is simply a pointer to an argument and thus it is not const. Please keep in mind, though that &p2 is pointer to local variable and it is never safe to return that.

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
3

When you have a "const" function, you are pretty much promising that "We will not change the object instance in this call". The compiler makes this a const T* this for that type of function (where T is the type of your class, e.g Player).

Obviously, returning a pointer to something that is const as as a non-const pointer is a breach of the rule - because once some code has a non-const pointer to your object, the code can modify the object... Which breaks the promise that "this function won't modify".

So adding const to the return type from function is the right solution here.

You probably also want to change your code so that it takes a const *Player p2 as input - your current code returns a pointer to a local variable [it happens to be an argument, but it's the same principle - it doesn't exist when the function call has returned].

Edit: Unless you are actually returning a copy of something (e.g. an integer, string or a new structure allocated with for example new) in a function with const attribute, the return type should be const.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Ah I see. So does the function allow me to return a pointer to p2 because it is a pointer to a local variable, therefore the compiler won't make it a const pointer? – Kakalokia Feb 06 '13 at 16:22
  • 2
    You are "allowed" to return a pointer to something that isn't const from a const function - it's just not usually a good idea if that returned value is a pointer or reference to something INSIDE the object itself [e.g. `this` or `&this->something` in the case of a ponter] - because that means the calling code can later modify what you promised would not be modified. – Mats Petersson Feb 06 '13 at 16:29