Programming Language & Its Applications β C++ Constructs with Objects and Classes, NEC licence examination syllabus (Nepal Engineering Council).
this PointerEvery member function secretly receives a pointer to the object it was called on.
this is what makes method chaining possible, and method chaining is everywhere you look β jQuery's $(x).addClass().fadeIn().show(), SQL query builders like db.table("users").where("age", 18).orderBy("name"), and every "fluent interface" in every language. All of them work by returning a reference to the object itself. Python makes the same pointer explicit as the self parameter you must type out; C++ hides it and calls it this. Search "fluent interface builder pattern" to see how far the idea goes β some libraries build entire configuration DSLs from nothing but returning *this.this is#include <iostream>
class Box {
int width, height;
public:
Box(int w, int h) : width(w), height(h) {}
/* 1. disambiguating a shadowing parameter */
void setWidth(int width) {
this->width = width; /* member = parameter */
}
/* 2. these two are identical */
int getW1() const { return width; }
int getW2() const { return this->width; }
/* 3. passing the object itself to something else */
void printAddress() const {
std::cout << "this = " << this << "\n";
}
/* 4. comparing identity, not value */
bool isSameObject(const Box &other) const {
return this == &other;
}
int area() const { return width * height; }
};
int main() {
Box a(4, 5), b(4, 5);
a.printAddress(); b.printAddress();
a.setWidth(10);
std::cout << "a area = " << a.area()
<< " (getW1=" << a.getW1()
<< " getW2=" << a.getW2() << ")\n";
std::cout << std::boolalpha;
std::cout << "a same as a? " << a.isSameObject(a) << "\n";
std::cout << "a same as b? " << a.isSameObject(b)
<< " (equal values, different objects)\n";
return 0;
}
Output:
this = 0x7ffd1a2b3410
this = 0x7ffd1a2b3418
a area = 50 (getW1=10 getW2=10)
a same as a? true
a same as b? false (equal values, different objects)
*this#include <iostream>
#include <string>
class Query {
std::string tbl, cond, ord;
int lim = 0;
public:
Query& from(const std::string &t) { tbl = t; return *this; }
Query& where(const std::string &c) { cond = c; return *this; }
Query& orderBy(const std::string &o){ ord = o; return *this; }
Query& limit(int n) { lim = n; return *this; }
std::string build() const {
std::string s = "SELECT * FROM " + tbl;
if (!cond.empty()) s += " WHERE " + cond;
if (!ord.empty()) s += " ORDER BY " + ord;
if (lim > 0) s += " LIMIT " + std::to_string(lim);
return s;
}
};
/* the BROKEN version: returns by value */
class BadCounter {
int n = 0;
public:
BadCounter inc() { ++n; return *this; } /* COPY */
int get() const { return n; }
};
class GoodCounter {
int n = 0;
public:
GoodCounter& inc() { ++n; return *this; } /* alias */
int get() const { return n; }
};
int main() {
std::cout << Query()
.from("students")
.where("marks > 80")
.orderBy("marks DESC")
.limit(10)
.build() << "\n";
BadCounter bad; bad.inc().inc().inc();
GoodCounter good; good.inc().inc().inc();
std::cout << "bad = " << bad.get() << " (expected 3)\n";
std::cout << "good = " << good.get() << "\n";
return 0;
}
Output:
SELECT * FROM students WHERE marks > 80 ORDER BY marks DESC LIMIT 10
bad = 1 (expected 3)
good = 3
*this. Every assignment operator you write must return ClassName& so that a = b = c works β that chain is built into the language's expectations, which is why operator= returning void compiles but breaks idiomatic code.
this in operator overloading and self-assignment#include <iostream>
#include <cstring>
class Text {
char *buf;
void copyFrom(const char *s) {
buf = new char[std::strlen(s) + 1];
std::strcpy(buf, s);
}
public:
Text(const char *s = "") { copyFrom(s); }
Text(const Text &o) { copyFrom(o.buf); }
~Text() { delete[] buf; }
Text& operator=(const Text &o) {
/* THE SELF-ASSIGNMENT GUARD.
Without it, `t = t` deletes buf and then copies
from the freed pointer β use after free. */
if (this == &o) return *this;
delete[] buf;
copyFrom(o.buf);
return *this; /* enables a = b = c */
}
Text& append(const char *s) {
char *nb = new char[std::strlen(buf)+std::strlen(s)+1];
std::strcpy(nb, buf); std::strcat(nb, s);
delete[] buf; buf = nb;
return *this;
}
void show() const { std::cout << buf << "\n"; }
};
int main() {
Text a("Nepal"), b, c;
b = c = a; /* chained assignment */
std::cout << "a="; a.show();
std::cout << "b="; b.show();
std::cout << "c="; c.show();
a = a; /* survives thanks to the guard */
std::cout << "after a=a: "; a.show();
a.append(" Engineering").append(" Council");
std::cout << "chained append: "; a.show();
return 0;
}
Output:
a=Nepal
b=Nepal
c=Nepal
after a=a: Nepal
chained append: Nepal Engineering Council
this β legal but sharpthis being a pointer rather than a reference is a historical artefact β references were added to C++ after this already existed. In C++11 the picture got richer with ref-qualified member functions, where f() & and f() && let you write different code depending on whether the object is a temporary. And in a lambda, [this] versus [*this] captures a pointer versus a copy β a distinction that causes real dangling-pointer bugs in asynchronous code, since the object may die before the lambda runs. Search "lambda capture this dangling"; it is a live bug class in modern C++.this as the implicit pointer to the invoking object and state its type (C* const, or const C* const in a const function). Its three standard uses are asked directly: disambiguating a shadowed member, returning *this for chaining, and the self-assignment check in operator=. Explain why static member functions have no this. The return-by-reference versus return-by-value chaining bug is an excellent trace question.Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Loadingβ¦