I\'ve recently came across this strange function in some class:
void* getThis() {return this;}
And later in the code it is sometimes used like
Of course, the pointer values can be different! Below an example which demonstrates the issue (you may need to use derived1
on your system instead of derived2
to get a difference). The point is that the this
pointer typically gets adjusted when virtual, multiple inheritance is involved. This may be a rare case but it happens.
One potential use case of this idiom is to be able to restore objects of a known type after storing them as void const*
(or void*
; the const
correctness doesn't matter here): if you have a complex inheritance hierarchy, you can't just cast any odd pointer to a void*
and hope to be able to restore it to its original type! That is, to easily obtain, e.g., a pointer to base
(from the example below) and convert it to void*
, you'd call p->getThis()
which is a lot easier to static_cast
and get a void*
which can be safely cast to a base*
using a static_cast
: you can reverse the implicit conversion but only if you cast back to the exact type where the original pointer came from. That is, static_cast
where d
is a pointer to an object of a type derived from base
is illegal but static_cast
is legal.
Now, why is the address changing in the first place? In the example base
is a virtual base class of two derived classes but there could be more. All subobjects whose class virtually inherits from base
will share one common base
subject in object of a further derived class (concrete
in the example below). The location of this base
subobject may be different relative to the respective derived subobject depending on how the different classes are ordered. As a result, the pointer to the base
object is generally different from the pointers to the subobjects of classes virtually inheriting from base
. The relevant offset will be computed at compile-time, when possible, or come from something like a vtable at run-time. The offsets are adjusted when converting pointers along the inheritance hierarchy.
#include
struct base
{
void const* getThis() const { return this; }
};
struct derived1
: virtual base
{
int a;
};
struct derived2
: virtual base
{
int b;
};
struct concrete
: derived1
, derived2
{
};
int main()
{
concrete c;
derived2* d2 = &c;
void const* dptr = d2;
void const* gptr = d2->getThis();
std::cout << "dptr=" << dptr << " gptr=" << gptr << '\n';
}