this: the implicit parameter in OOP
February 11, 2025
I was recently reminded that the variable this
is an implicit parameter passed to all methods in OOP such as C++. We can observe this by comparing a regular function vs a method
belonging to some class:
#include <iostream>
void greet() {
std::cout << "Hello World\n";
}
class Human {
public:
void greet() {
std::cout << "Hello World\n";
}
};
int main() {
greet();
Human human = Human();
human.greet();
}
Output:
$ g++ test.C
$ ./a.out
Hello World
Hello World
Both may output the same thing but under the hood is where the differences shines. Note: I’ll be only showing the code of interest.
For greet
:
Dump of assembler code for function _Z5greetv:
0x0000000000401126 <+0>: push %rbp
0x0000000000401127 <+1>: mov %rsp,%rbp
0x000000000040112a <+4>: mov $0x402280,%esi
For Human::greet
:
Dump of assembler code for function _ZN5Human5greetEv:
0x000000000040115c <+0>: push %rbp
0x000000000040115d <+1>: mov %rsp,%rbp
0x0000000000401160 <+4>: sub $0x10,%rsp
0x0000000000401164 <+8>: mov %rdi,-0x8(%rbp)
0x0000000000401168 <+12>: mov $0x402280,%esi
For greet
(_Z5greetv
), we can immediately tell that the function takes in no arguments both by the mangled name (i.e. mangled name ends with v
to indicate its parameter is void
)
and from the disassembled code. However, the same cannot be said for Human::greet
. The mangled name _ZN5Human5greetEv
does suggest that the method does not take in any parameter
and hence the suffix v
for void
. But observe the following line in <+8>
:
mov %rdi,-0x8(%rbp)
This
is our implicit argument, this
, which contains the address of the object itself. We can observe this via gdb:
(gdb) p &human
$2 = (Human *) 0x7fffffffdc4f
...
(gdb) i r rdi
rdi 0x7fffffffdc4f 140737488346191
Notice our rdi
register contains the same address as our object human
: 0x7fffffffdc4f
.