189. Shadowing Resolution

In clean code, we often want function parameters to have descriptive names (like speed or config). However, if a class has a member variable with the exact same name, the parameter "shadows" the member. Writing speed = speed; does nothing (it assigns the parameter to itself).

To fix this, we use the this pointer to explicitly refer to the member variable: this->speed = speed;.

Your task is to implement a class Timer.

  1. Private member: int period (initialized to 0).
  2. Method void setPeriod(int period):
    • The argument name MUST be period.
    • You must use this-> to assign the argument to the member.
  3. Method void log(): Print Timer Period: <period> ms.

Program Flow:

  1. Instantiate Timer.
  2. Read integer N.
  3. Loop N times.
  4. Read integer p.
  5. Call timer.setPeriod(p).
  6. Call timer.log().

Input Format:

  • First line: Integer N.
  • Next N lines: Integer p.
  • Input is provided via standard input (stdin).

Output Format:

  • Timer Period: <value> ms
  • Each output on a new line.

Example: 

Example 1

Input:

2
100
500

Output:

Timer Period: 100 ms
Timer Period: 500 ms

Constraints:

  • The argument of setPeriod must be named period (same as the member).
  • Must use this->period to resolve the conflict.

 

 

 

Need Help? Refer to the Quick Guide below

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.