Ch13.7: The this Pointer

中文(简体)

1. Every Member Function Quietly Receives the Object

When you write c.add(2), the compiler has to tell add which counter to add to. It does that by passing the object as an extra argument — the first one, not visible in the parameter list, and reachable inside the function through the keyword this:


c.add(2);        // what you write

// what the member function actually receives:
//    (counter *this, ::std::int_least32_t n)

this is a pointer to that object. So this->value_ and (*this).value_ and plain value_ are three spellings of the same member. You rarely need to write it; the three cases where you do are below.

2. Case 1: A Parameter Hides a Member

If a parameter has the same name as a data member, the parameter wins and the member disappears from view. this-> brings it back:


counter &set(::std::int_least32_t value) noexcept
{
	this->value_ = value;   // member on the left, parameter on the right
	return *this;
}

Many people avoid the question entirely by naming the parameter differently (n, or new_value) — that works too, and gives shorter names. Either way, this-> is the way to be explicit when the two names collide.

3. Case 2: Returning the Object You Were Called On

*this is the object itself, not a pointer to it. Returning a reference to it lets the caller chain calls on the same object, because every call in the chain is a member function on the object the previous call returned:


#include <fast_io.h>
#include <cstdint>
using namespace ::fast_io::io;

class counter
{
public:
	explicit counter(::std::int_least32_t value) noexcept : value_{value}
	{
	}

	// `value` hides the member, so the member needs this-> .
	counter &set(::std::int_least32_t value) noexcept
	{
		this->value_ = value;
		return *this;
	}

	counter &add(::std::int_least32_t n) noexcept
	{
		value_ += n;
		return *this; // the object we were called on
	}

	::std::int_least32_t value() const noexcept
	{
		return value_;
	}

	bool same_as(counter const &other) const noexcept
	{
		return this == &other;
	}

private:
	::std::int_least32_t value_{};
};

int main()
{
	counter c{0};
	c.add(1).add(2).add(3); // chaining: each call returns *this
	println("after chaining: ", c.value());

	c.set(10);
	println("after set(10):  ", c.value());

	counter d{10};
	println("c.same_as(d) = ", c.same_as(d));
	println("c.same_as(c) = ", c.same_as(c));
}

after chaining: 6
after set(10):  10
c.same_as(d) = 0
c.same_as(c) = 1

The return type is counter & — a reference to the object itself, not a pointer and not a separate value, so c.add(1).add(2) reads like c.add(1); c.add(2); with the object written once. If the chain may be called on a const object, use counter const & and a const member function (Ch13.3).

4. Case 3: Do You Mean This Object?

A member function can compare the object it was called on against another one. this is the address of the first, &other the address of the second, so this == &other asks whether they are the same object — not whether their contents are equal:


bool same_as(counter const &other) const noexcept
{
	return this == &other;   // one object, addressed twice?
}

In c.same_as(d) the addresses differ and the answer is 0; in c.same_as(c) both names refer to one object and the answer is 1. Comparing the contents would be a different function: return value_ == other.value_;. Both are useful; make sure you know which question you asked.

5. In a const Member Function, this Is const

This is the mechanism behind Chapter 13.3. The keyword this follows the const of the member function:


::std::int_least32_t value() const noexcept   // inside: this is counter const *
{
	return value_;                        // so value_ is const here too
}

A const member function therefore cannot assign to a member, and cannot call a non-const member function — the object it holds is read-only, and every member reached through it is read-only too.

this does not exist in a static member function (Ch13.9). A static member function is not called on an object, so there is no object to point at:

error: 'this' is unavailable for static member functions

And of course it does not exist in a free function either:


error: invalid use of 'this' in non-member function
Do not overuse this. this->value_ where plain value_ means the same thing adds noise that readers have to filter. Write it when it disambiguates (Case 1), when it is the value you need (Cases 2 and 3), or when a code editor’s syntax colouring is the only thing telling your members apart — which no reader can see.