The "this" Pointer (Self-Reference)

cardimg

Inside every non-static member function, C++ provides a hidden pointer named this.

It points to the address of the object that called the function.

Think of it as the word "Me" or "My" in English.

  • If Alice says "My pocket", she refers to Alice's pocket.

  • If Bob says "My pocket", he refers to Bob's pocket.

  • The code (the sentence) is the same, but the context (this) changes depending on who speaks.

Syntax & Usage

A. Resolving Name Conflicts

The most common use is when a function argument has the same name as a class member variable. this-> explicitly tells the compiler "use the member variable, not the local argument."

class Servo {
    int pos; // Member variable
public:
    // Argument 'pos' shadows member 'pos'
    void setPos(int pos) {
        // pos = pos;      // WRONG: Assigns argument to itself.
        this->pos = pos;   // RIGHT: "My pos" = argument "pos".
    }
};

B. Method Chaining (Fluent Interfaces)

You can return *this (the object itself) to chain function calls on a single line. This is common in configuration patterns (Builders).

class LCD {
public:
    LCD& clear() { 
        /* clear screen */ 
        return *this; // Return reference to myself
    }
    LCD& setCursor(int x, int y) { 
        /* move cursor */ 
        return *this; 
    }
    LCD& print(const char* s) { 
        /* print text */ 
        return *this; 
    }
};

int main() {
    LCD screen;
    // Chaining calls:
    screen.clear().setCursor(0, 1).print("Ready");
}

Under the Hood (The Hidden Argument)

How does one function code work for 100 different objects?

The compiler secretly modifies your function. It adds a hidden first argument: the pointer to the object.

Your C++ Code

What the Compiler Actually Generates (C-Style)

void Servo::move(int p) { ... }

void Servo_move(Servo* const this, int p) { ... }

myServo.move(90);

Servo_move(&myServo, 90);

  • Note: This is why Static Functions do not have this. They are not passed this hidden argument, so they don't know which object to touch.

Relevance in Embedded/Firmware

A. RTOS Tasks & C-Style Callbacks

Most RTOSs (FreeRTOS, ThreadX) and Hardware Drivers use C APIs. They allow you to pass a void* context parameter to callbacks.

We pass this so the static C callback knows which C++ object to restore.

class Button {
public:
    void onClick() { printf("Clicked!\n"); }

    // Static wrapper compatible with C-style callback
    static void callback_wrapper(void* context) {
        // 1. Cast 'void*' back to 'Button*'
        Button* self = static_cast<Button*>(context);
        
        // 2. Call the actual member function using the restored pointer
        self->onClick();
    }
};

// Registering interrupt: pass 'this' as the context
attachInterrupt(PIN_5, Button::callback_wrapper, this);

B. Self-Assignment Check

In assignment operators (operator=), you must check if the user is trying to assign an object to itself (obj = obj;). If you don't check this, you might delete your own data before copying it (Disaster).

Buffer& operator=(const Buffer& other) {
    if (this == &other) { // Am I copying myself?
        return *this;     // Do nothing.
    }
    // Proceed with copy...
}

Common Pitfalls (The Danger Zone)

Pitfall

Details

delete this

Is it legal? Yes. Is it dangerous? Extremely. If you write delete this;, the object destroys itself. Accessing any member variable afterwards causes a crash. Used rarely (e.g., in "Fire and Forget" tasks).

❌ Using in Static

Static functions belong to the class, not an instance. Trying to use this inside a static method causes a compile error: "invalid use of member in static member function".

❌ Capture in Lambdas

In C++11 Lambdas, using [=] captures variables by value, but it captures this as a pointer. If the object dies but the lambda runs later (async callback), accessing members via the captured this will crash (Use After Free).

Summary Checklist

  • Use this->variable to fix shadowing names.

  • Return *this to enable method chaining (obj.func1().func2()).

  • Pass this as void* context when integrating with C libraries or RTOS tasks.

  • Never access this inside a static function.

 

 

Concept understood? Let's apply and learn for real

Practice now