Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can 'this' pointer be different than the object's pointer?

Tags:

c++

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 so: bla->getThis() (Where bla is a pointer to an object of the class where this function is defined.) And I can't seem to realize what this can be good for. Is there any situation where a pointer to an object would be different than the object's this (where bla != bla->getThis())?

It seems like a stupid question but I wonder if I'm missing something here..

like image 411
kipod Avatar asked Aug 21 '13 22:08

kipod


People also ask

What is the difference between a pointer and an object?

A pointer stores the memory address of a variable. When you pass a pointer (to an object) for a function as a parameter, it means that function will have access to that object through it's memory address instead of a new object being created on the stack.

Why is this pointer used than object pointer?

Every object in C++ has access to its own address through an important pointer called this pointer. The this pointer is an implicit parameter to all member functions. Therefore, inside a member function, this may be used to refer to the invoking object.

Can pointers point to different types?

The pointers can point to any type if it is a void pointer. but the void pointer cannot be dereferenced. only if the complier knows the data type of the pointer variable, it can dereference the pointer and perform the operations. Save this answer.

Can I change this pointer in C++?

In the early version of C++ would let 'this' pointer to be changed; by doing so a programmer could change which object a method was working on. This feature was eventually removed, and now this in C++ is an r-value.


1 Answers

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<base*>(p) and get a void* which can be safely cast to a base* using a static_cast<base*>(v): 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<base*>(static_cast<void*>(d)) where d is a pointer to an object of a type derived from base is illegal but static_cast<base*>(d->getThis()) 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 <iostream>

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';
}
like image 118
Dietmar Kühl Avatar answered Oct 12 '22 03:10

Dietmar Kühl