Reputation: 57
I have one question about C++ programming. If I have two classes called parent and child respectively. The child is derived from the parent. When I create an object either on the stack or the heap, it has to be initialized by the constructors of both classes. I find that the "this" ptrs are pointing to different addresss if you step into the constructor function while debugging. The "this" of the child class is pointing to the object, but what is the parent's "this" pointing to?
Here is my code for reference. FYI: I use g++ 10.3 and gdb 9.2 on Ubuntu 20.04
#include <iostream>
class parent
{
public:
int attribute0, attribute1, attribute2, attribute3;
parent():attribute0(0), attribute1(1), attribute2(2), attribute3(3){}
};
class child : parent
{
public:
int attribute4;
child(int arg) : parent() {
attribute4 = arg;
}
};
int main(){
auto obj0 = new child(100);
delete obj0;
child obj1(80);
return 0;
}
Upvotes: 1
Views: 1545
Reputation: 9682
#include <iostream>
class parent
{
public:
int attribute0, attribute1, attribute2, attribute3;
parent():attribute0(0), attribute1(1), attribute2(2), attribute3(3){}
};
class child : parent
{
public:
int attribute4;
child(int arg) : parent() {
attribute4 = arg;
}
};
int main(){
std::cout << "attribute0: " << offsetof(parent, attribute0) << "\n";
std::cout << "attribute1: " << offsetof(parent, attribute1) << "\n";
std::cout << "attribute2: " << offsetof(parent, attribute2) << "\n";
std::cout << "attribute3: " << offsetof(parent, attribute3) << "\n";
std::cout << "attribute4: " << offsetof(child, attribute4) << "\n";
return 0;
}
If you really want to know how the data is packaged, you can use offsetof on the member variables to see how your compiler is doing it (it may give you some warnings though, so it's not a reliable way to use offsetof, but for educational purposes this is fine). https://godbolt.org/z/6dGxT9e6b
attribute0: 0
attribute1: 4
attribute2: 8
attribute3: 12
attribute4: 16
'this' points to the start of the object in memory (in this case, the same location as attribute0).
If you add a virtual method to the parent class, e.g.
class parent
{
public:
int attribute0, attribute1, attribute2, attribute3;
parent():attribute0(0), attribute1(1), attribute2(2), attribute3(3){}
virtual void func() {}
};
Then you will notice an extra 8bytes at the start:
attribute0: 8
attribute1: 12
attribute2: 16
attribute3: 20
attribute4: 24
This 8bytes is to store the pointer to the vtable (for 32bit code, this might be a 4byte offset)
If you really want to see that 'this' is the same for both parent & child classes, just print out the value and take a look:
#include <iostream>
class parent
{
public:
int attribute0, attribute1, attribute2, attribute3;
parent():attribute0(0), attribute1(1), attribute2(2), attribute3(3){}
void printParent() {
std::cout << "parent " << this << ' ' << &attribute0 << "\n";
}
};
class child : public parent
{
public:
int attribute4;
child(int arg) : parent() {
attribute4 = arg;
}
void printChild() {
std::cout << "child " << this << ' ' << &attribute4 << "\n";
}
};
int main(){
child* c = new child(4);
c->printParent();
c->printChild();
return 0;
}
Prints:
parent 0x1f98eb0 0x1f98eb0
child 0x1f98eb0 0x1f98ec0
So, 'this' of the parent, 'this' of the child, and attribute0, all point to the same memory location. The address of attribute4 is exactly 16bytes after 'this', which is what offsetof told us earlier.
Upvotes: 3
Reputation: 67382
this
always points to the beginning of the instance of whatever type it (this
) is.
That probably sounds confusing, so let's try to visualize it. Now what I'm about to describe isn't part of the C++ standard, and every implementation is free to change it as they wish or need, but it's generally some form of this:
-----------------------------------------------------
| pre-parent | parent data | pre-child | child data |
-----------------------------------------------------
Inside parent::parent()
, this
is of type const parent *
and so points to the beginning of the parent data. However inside child::child()
, this
is of type const child *
and so points to the beginning of the child data. You can ignore the pre-parent and pre-child portions, those are implementation defined chunks of memory that describe the allocation, virtual table, debug sentries, etc.
So now it should be obvious why you can access the entire object through the parent's this
(since all the child data is after it and thus accessible through regular member access), but you can't access the entire object through the child this
without first casting it up to the full object.
It should also be obvious why the two this
pointers don't point to the same address (though they could if the parent had no fields and the compiler didn't insert any pre-child data, so no debug mode).
Upvotes: 2
Reputation: 238311
Where does “this” point to in parent class (c++)?
In all member functions, this
always points to the object whose member function is being called. This is regardless of type hierarchies. Within member function of a base, this
points to the base sub object.
Upvotes: 5