Classes and Objects

The this Pointer

Each non static member function is supplied with a hidden pointer to the object on which the function was invoked. This pointer is named this. The compiler provides this pointer for you, and it is never included in the ordinary parameters of the function.

In a member function, when data members are referenced by name, the compiler silently pre-modifies the name as an access through this. The two ways are thus equivalent. The program below shows the two styles side by side.

#include <iostream>

class Counter
{
private:
    int value{};

public:
    void set(int n)
    {
        value = n;        // means this->value = n
    }

    void setExplicit(int n)
    {
        this->value = n;  // written out in full
    }

    void print()
    {
        std::cout << value << '\n';
    }
};

int main()
{
    Counter c{};
    // Call the setter to update the object state
    c.set(5);
    c.print();
    c.setExplicit(10);
    c.print();

    return 0;
}

In set, the identifier value is dereferenced by searching through the object this points to. In setExplicit, the same dereference is shown as using the arrow operator. Both calls from main put a number into the private member of the same object c, and the two print statements display 5 followed by 10. For normal member access, the explicit form is never needed, but it does make the hidden pointer visible.

The pointer comes into play when there is a parameter or local variable with the same name as the data member. If this does not exist, then simply using the name would refer to the parameter, without changing the data member.

#include <iostream>

class Point
{
private:
    int x{};
    int y{};

public:
    void set(int x, int y)
    {
        // Refer to the current object explicitly through this
        this->x = x;
        this->y = y;
    }

    void print()
    {
        std::cout << this->x << ',' << this->y << '\n';
    }
};

int main()
{
    Point p{};
    p.set(3, 7);
    p.print();

    return 0;
}

The arguments of set are also named x and y; inside the function the simple names refer to the arguments. To use the data members of the object, the explicit pointer this-> must be used: after the call p.set(3, 7) the data members will be 3 and 7 and then print will output 3,7. If this-> were omitted, each argument would be assigned to itself and the members would be left with their initial value of zero.

Because this is a pointer, the object it points to can be accessed using the unary * operator. The expression *this returns a reference to the object whose member function has been invoked. Another use is to return that object so that multiple calls can be chained.

#include <iostream>

class Counter
{
private:
    int value{};

public:
    Counter& add(int n)
    {
        value += n;
        return *this;
    }

    void print()
    {
        std::cout << value << '\n';
    }
};

int main()
{
    Counter c{};
    // Call this function with the provided arguments
    c.add(2).add(3).add(5);
    c.print();

    return 0;
}

Each call to add changes the member value, then returns *this. The reference returned is the same object, so the next .add can be immediately invoked on the same object (c). The three calls hence effectively sum 2 + 3 + 5 to the single object c, and the last print displays 10:0.

The fact that the function returns *this only works because this is already the object the method was invoked on.

The function doesn't generate another object.

The pointer this is constant in the sense that a member function cannot change which object it is pointing to. Any such assignment, for example this = &other;, will be caught by the compiler. Though the pointer can be used to access the object, the address contained within it cannot be changed while the function is executing.

The const method receives this as a const ClassName*, so only const methods can be called through it. This distinction is a language rule of const-correctness and assures us that when the object is in a const state, it cannot be changed even by an explicit this->.

The pointer is in every non-static member function regardless of whether the programmer ever uses the keyword this. The simple name of a member is simply a safe alternative for the full expression that traverses the pointer. In the case of name clash, or simply to return the object itself, the explicit form clears out any confusion and reveals exactly what is going on.

Exercise: The this PointerStarter code, hints and solutionOpenClose
Guided practiceBeginner · 10–15 min

Practice: The this Pointer

Work through the mission, reveal hints only when needed, and compare your result with the model solution.

Your challenge

Add a const member isSameObject(const Point*) that compares its argument with this. Call p.isSameObject(&p) and explain the lifetime and ownership of this.

Mission checklist

  1. Run the starter as a baseline, then predict the change requested in Your challenge.
  2. Make that change in your editor; use the lesson-specific hints if you need help.
  3. Compile and run your answer, then compare with the worked solution and explain the result.

Starter program

This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.

#include <iostream>

class Point
{
private:
    int x{};
    int y{};

public:
    void set(int x, int y)
    {
        // Refer to the current object explicitly through this
        this->x = x;
        this->y = y;
    }

    void print()
    {
        std::cout << this->x << ',' << this->y << '\n';
    }
};

int main()
{
    Point p{};
    p.set(3, 7);
    p.print();

    return 0;
}

Hints

Hint 1

In set(int x, int y), the parameter names hide the member names. this->x refers to the current object's member, while plain x refers to the parameter.

Hint 2

Inside the const member, this can be compared with the const Point* parameter. Use &p at the call site; no allocation or deletion is involved.

Worked solution

The added const member compares this with an address supplied by the caller. p.isSameObject(&p) is true because this refers to p during the call. this is non-owning; p has automatic lifetime and must not be deleted through it.

#include <iostream>

class Point
{
private:
    int x{};
    int y{};

public:
    void set(int x, int y)
    {
        // Refer to the current object explicitly through this
        this->x = x;
        this->y = y;
    }

    bool isSameObject(const Point* other) const { return this == other; }

    void print()
    {
        std::cout << this->x << ',' << this->y << '\n';
    }
};

int main()
{
    Point p{};
    p.set(3, 7);
    p.print();

    std::cout << "This is p: " << p.isSameObject(&p) << '\n';
    return 0;
}

Example output

3,7
This is p: 1

0 comments

No comments yet. Be the first.

Add a comment

About CppLearn

CppLearn is an interactive, free reference for modern C++. In each lesson, you'll find out how the language works, rather than just lines of code that you can copy and paste. We cover concepts starting from beginner lessons on fundamentals and proceed to templates, move semantics, smart pointers, and areas that usually trap or scare C++ learners.