CS 70

The this Pointer in Member Functions

Let's look back at our first printElephant function. It currently accesses a (public!) data member, name_, but perhaps this data member should have been private, in which case printElephant would need to be a member function for the Elephant class, Elephant::print.

Let's compare the two approaches. On the left we have the global function, and on the right the member function (which would also need to be declared in the class definition).

void printElephant(const Elephant* ePtr) {
    cout << "Elephant named " << ePtr->name_ << endl;
}

which is called with

printElephant(&charlie);
void Elephant::print() const {
    cout << "Elephant named " << name_ << endl;
}

which is called with

charlie.print();

Both pieces of code do the same thing, and our example use has both of them operating on the elephant charlie. But one thing is interesting: an argument is passed into the function in the left-hand version, but the right-hand version shows a function that takes no arguments.

How does the member function know what object it's running on?

  • Dog speaking

    Magic?

  • LHS Cow speaking

    There is no magic here. Just hidden machinery.

  • Alien speaking

    That's what my people tell more primitive beings about transporter technology. Sometimes.

Behind the scenes, when we write any member function, it's as if the function has a hidden extra argument. The name and type of the hidden extra argument is

  • const Elephant* this for const member functions
  • Elephant* this for non-const member functions

In the code for print(), when we say name_, it's as if we wrote this->name_. And when we call print().

And, when we call a member function, it passes the address of the object we called it on. So when we write charlie.print(), it's as almost as if we wrote Elephant::print(&charlie), except that the ”this” argument is a secret hidden argument.

  • Duck speaking

    So basically, behind the scenes, the member function works almost exactly like the global function.

  • LHS Cow speaking

    Yes.

  • Duck speaking

    But why isn't this a reference? That's the more C++-style printElephant function, not the one that takes a pointer.

  • Bjarne speaking

    I introduced this in 1979, I didn't introduce references until 1985. By that point there was more than five years of code where this was a pointer. And it's not like you need to say this very often anyway.

  • LHS Cow speaking

    And now we've had 37 more years of living with it as a pointer. Gah.

If you want the actual object a member function was called on, you need to say *this, because this is a pointer to the target object, not the object itself.

All of the following are valid ways to access the age_ member variable of an Elephant inside a member function, but which is best?

  • RHS Cow speaking

    Sometimes when we look at student code, we see students wanting to write this->age_ or (*this).age_ because they think it's more explicit. But it's not. It's just more typing.

  • LHS Cow speaking

    The trailing underscore helps us remember that it's a member variable, so adding in this-> as well is just noise.

  • RHS Cow speaking

    Okay, we've made some good progress and we're nearly done. Let's head back up to the parent page to check our progress and maybe take a break.

(When logged in, completion status appears here.)