"this" 在 parent class (c++) 中指向哪里?
Where does "this" point to in parent class (c++)?
我有一个关于 C++ 编程的问题。如果我有两个 class 分别称为 parent 和 child。 child 派生自 parent。当我在堆栈或堆上创建 object 时,它必须由两个 class 的构造函数初始化。我发现如果你在调试时进入构造函数,“this”指针指向不同的地址。 childclass的“this”指向object,但是parent的“this”指向什么?
这是我的代码供参考。仅供参考:我在 Ubuntu 20.04
上使用 g++ 10.3 和 gdb 9.2
#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;
}
Where does “this” point to in parent class (c++)?
在所有成员函数中,this
总是指向被调用成员函数的对象。这与类型层次结构无关。在基的成员函数中,this
指向基的子对象。
this
总是指向它 (this
) 是什么类型的实例的开头。
这听起来可能令人困惑,所以让我们试着想象一下。现在我要描述的不是 C++ 标准的一部分,每个实现都可以根据自己的意愿或需要自由更改它,但通常是这样的某种形式:
-----------------------------------------------------
| pre-parent | parent data | pre-child | child data |
-----------------------------------------------------
在 parent::parent()
中,this
属于 const parent *
类型,因此指向父数据的开头。但是在 child::child()
中,this
是 const child *
类型,因此指向子数据的开头。您可以忽略前父部分和前子部分,这些是实现定义的内存块,用于描述分配、虚拟 table、调试哨兵等
所以现在应该很明显为什么你可以通过父对象的 this
访问整个对象(因为所有子数据都在它之后,因此可以通过常规成员访问访问),但你不能访问整个对象通过子对象 this
而不是先将其转换为完整对象。
为什么两个 this
指针不指向同一个地址也应该很明显(尽管如果父项没有字段并且编译器没有插入任何前子数据,它们可以,所以没有调试模式)。
#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;
}
如果你真的想知道数据是如何打包的,你可以在成员变量上使用offsetof,看看你的编译器是如何做的(虽然它可能会给你一些警告,所以它不是一种使用 offsetof 的可靠方法,但出于教育目的,这很好)。 https://godbolt.org/z/6dGxT9e6b
attribute0: 0
attribute1: 4
attribute2: 8
attribute3: 12
attribute4: 16
'this'指向对象在内存中的开始(在本例中,与attribute0相同的位置).
如果您向父级添加虚方法 class,例如
class parent
{
public:
int attribute0, attribute1, attribute2, attribute3;
parent():attribute0(0), attribute1(1), attribute2(2), attribute3(3){}
virtual void func() {}
};
然后你会注意到开头多了8个字节:
attribute0: 8
attribute1: 12
attribute2: 16
attribute3: 20
attribute4: 24
这8bytes是存放指向vtable的指针(对于32位代码,这可能是4byte的偏移量)
如果你真的想看到 'this' 对于父子 class 是相同的,只需打印出值并看一下:
#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;
}
打印:
parent 0x1f98eb0 0x1f98eb0
child 0x1f98eb0 0x1f98ec0
所以,parent的'this',child的'this',attribute0,都指向同一个内存位置。 attribute4的地址恰好在'this'之后的16bytes,这是offsetof前面告诉我们的
我有一个关于 C++ 编程的问题。如果我有两个 class 分别称为 parent 和 child。 child 派生自 parent。当我在堆栈或堆上创建 object 时,它必须由两个 class 的构造函数初始化。我发现如果你在调试时进入构造函数,“this”指针指向不同的地址。 childclass的“this”指向object,但是parent的“this”指向什么?
这是我的代码供参考。仅供参考:我在 Ubuntu 20.04
上使用 g++ 10.3 和 gdb 9.2#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;
}
Where does “this” point to in parent class (c++)?
在所有成员函数中,this
总是指向被调用成员函数的对象。这与类型层次结构无关。在基的成员函数中,this
指向基的子对象。
this
总是指向它 (this
) 是什么类型的实例的开头。
这听起来可能令人困惑,所以让我们试着想象一下。现在我要描述的不是 C++ 标准的一部分,每个实现都可以根据自己的意愿或需要自由更改它,但通常是这样的某种形式:
-----------------------------------------------------
| pre-parent | parent data | pre-child | child data |
-----------------------------------------------------
在 parent::parent()
中,this
属于 const parent *
类型,因此指向父数据的开头。但是在 child::child()
中,this
是 const child *
类型,因此指向子数据的开头。您可以忽略前父部分和前子部分,这些是实现定义的内存块,用于描述分配、虚拟 table、调试哨兵等
所以现在应该很明显为什么你可以通过父对象的 this
访问整个对象(因为所有子数据都在它之后,因此可以通过常规成员访问访问),但你不能访问整个对象通过子对象 this
而不是先将其转换为完整对象。
为什么两个 this
指针不指向同一个地址也应该很明显(尽管如果父项没有字段并且编译器没有插入任何前子数据,它们可以,所以没有调试模式)。
#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;
}
如果你真的想知道数据是如何打包的,你可以在成员变量上使用offsetof,看看你的编译器是如何做的(虽然它可能会给你一些警告,所以它不是一种使用 offsetof 的可靠方法,但出于教育目的,这很好)。 https://godbolt.org/z/6dGxT9e6b
attribute0: 0
attribute1: 4
attribute2: 8
attribute3: 12
attribute4: 16
'this'指向对象在内存中的开始(在本例中,与attribute0相同的位置).
如果您向父级添加虚方法 class,例如
class parent
{
public:
int attribute0, attribute1, attribute2, attribute3;
parent():attribute0(0), attribute1(1), attribute2(2), attribute3(3){}
virtual void func() {}
};
然后你会注意到开头多了8个字节:
attribute0: 8
attribute1: 12
attribute2: 16
attribute3: 20
attribute4: 24
这8bytes是存放指向vtable的指针(对于32位代码,这可能是4byte的偏移量)
如果你真的想看到 'this' 对于父子 class 是相同的,只需打印出值并看一下:
#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;
}
打印:
parent 0x1f98eb0 0x1f98eb0
child 0x1f98eb0 0x1f98ec0
所以,parent的'this',child的'this',attribute0,都指向同一个内存位置。 attribute4的地址恰好在'this'之后的16bytes,这是offsetof前面告诉我们的