编译器:class 实例化代码是如何编译的?
Compiler: How is class instantiation code compiled?
假设我们有(在 C++ 中):MyClass* x = new MyClass(10)
有人可以解释一下 'exactly' 编译器解析此语句时发生了什么吗? (我试着看了看红龙书,但找不到任何有用的东西)。
我想知道 stack/heap 或编译器的符号 table 中发生了什么。编译器如何跟踪 x
变量的类型?稍后对 x->method1(1,2)
的调用将如何解析为 MyClass 中的适当方法(为简单起见,假设没有继承,并且 MyClass
是我们仅有的 class)。
MyClass* x
是指向类型MyClass
的对象(实例)的指针的定义。该变量的内存是根据其定义的位置分配的:如果它是在方法中定义的,并且是局部变量,则使用堆栈。并且是存储地址的内存。
那么表达式new MyClass(10)
是一个命令,为一个对象(实例)本身在堆中分配内存,return地址存储在x
中。为了填充新对象 MyClass
的内存(设置其初始状态),自动执行特殊方法(至少一个) - 构造函数(或在某些情况下为多个) - 在您的示例中接收值 10
.
因为C++允许继承(这也是创建实例时执行多个构造函数的原因)所以有一些机制来确定应该调用哪个方法。您应该在某处阅读有关 Virtual method table.
的内容
在最简单的情况下(没有继承),变量类型 x
(指向类型 MyClass
的对象的指针)提供有关对象结构的所有必要信息。因此,x->method1(1,2)
或 (*x).method1(1,2)
提供成员 method1
的调用以使用参数 1
和 2
(存储在堆栈中)以及形成的数据来执行它对象的状态(存储在堆中),可通过 class 的任何非静态成员内的 this
指针访问。方法本身,当然不会存储在堆中。
更新:
你可以做例子来做同样的实验,比如:
#include <iostream>
#include <string>
using namespace std;
class MyClass
{
private:
int innerData;
long long int lastValue;
public:
MyClass() // default constructor
{
cout << "default constructor" << endl;
innerData = 42;
lastValue = 0;
}
MyClass(int data) // constructor with parameter
{
cout << "constructor with parameter" << endl;
innerData = data;
lastValue = 0;
}
int method1(int factor, int coefficient)
{
cout << "Address in this-pinter " << this << endl;
cout << "Address of innerData " << &innerData << endl;
cout << "Address of lastValue " << &lastValue << endl;
cout << "Address of factor " << &factor << endl;
lastValue = factor * innerData + coefficient;
return lastValue;
}
};
int main(void)
{
MyClass* x = new MyClass(10);
cout << "addres of object " << x << endl;
cout << "addres of pointer " << &x << endl;
cout << "size of object " << sizeof(MyClass) << endl;
cout << "size of pointer " << sizeof(x) << endl;
x->method1(1, 2);
}
C++ 确实有点讨厌,这已经在 C 中开始了。看看前 3 个标记:MyClass * x
。编译器必须查找 MyClass
以确定这是 而不是 乘法。既然是类型,那也不应该去查x
,而是直接在table符号后面加上x
(真的不能耽误)。在易于解析的语言的理想世界中,无需为解析的每个标记保持符号 table 最新。
在 x
的定义之后,=
发出初始化表达式的信号。这很容易解析:new
是一个明确的关键字,它不是一个位置 new
并且正在创建的类型就在那里。
假设我们有(在 C++ 中):MyClass* x = new MyClass(10)
有人可以解释一下 'exactly' 编译器解析此语句时发生了什么吗? (我试着看了看红龙书,但找不到任何有用的东西)。
我想知道 stack/heap 或编译器的符号 table 中发生了什么。编译器如何跟踪 x
变量的类型?稍后对 x->method1(1,2)
的调用将如何解析为 MyClass 中的适当方法(为简单起见,假设没有继承,并且 MyClass
是我们仅有的 class)。
MyClass* x
是指向类型MyClass
的对象(实例)的指针的定义。该变量的内存是根据其定义的位置分配的:如果它是在方法中定义的,并且是局部变量,则使用堆栈。并且是存储地址的内存。
那么表达式new MyClass(10)
是一个命令,为一个对象(实例)本身在堆中分配内存,return地址存储在x
中。为了填充新对象 MyClass
的内存(设置其初始状态),自动执行特殊方法(至少一个) - 构造函数(或在某些情况下为多个) - 在您的示例中接收值 10
.
因为C++允许继承(这也是创建实例时执行多个构造函数的原因)所以有一些机制来确定应该调用哪个方法。您应该在某处阅读有关 Virtual method table.
的内容在最简单的情况下(没有继承),变量类型 x
(指向类型 MyClass
的对象的指针)提供有关对象结构的所有必要信息。因此,x->method1(1,2)
或 (*x).method1(1,2)
提供成员 method1
的调用以使用参数 1
和 2
(存储在堆栈中)以及形成的数据来执行它对象的状态(存储在堆中),可通过 class 的任何非静态成员内的 this
指针访问。方法本身,当然不会存储在堆中。
更新:
你可以做例子来做同样的实验,比如:
#include <iostream>
#include <string>
using namespace std;
class MyClass
{
private:
int innerData;
long long int lastValue;
public:
MyClass() // default constructor
{
cout << "default constructor" << endl;
innerData = 42;
lastValue = 0;
}
MyClass(int data) // constructor with parameter
{
cout << "constructor with parameter" << endl;
innerData = data;
lastValue = 0;
}
int method1(int factor, int coefficient)
{
cout << "Address in this-pinter " << this << endl;
cout << "Address of innerData " << &innerData << endl;
cout << "Address of lastValue " << &lastValue << endl;
cout << "Address of factor " << &factor << endl;
lastValue = factor * innerData + coefficient;
return lastValue;
}
};
int main(void)
{
MyClass* x = new MyClass(10);
cout << "addres of object " << x << endl;
cout << "addres of pointer " << &x << endl;
cout << "size of object " << sizeof(MyClass) << endl;
cout << "size of pointer " << sizeof(x) << endl;
x->method1(1, 2);
}
C++ 确实有点讨厌,这已经在 C 中开始了。看看前 3 个标记:MyClass * x
。编译器必须查找 MyClass
以确定这是 而不是 乘法。既然是类型,那也不应该去查x
,而是直接在table符号后面加上x
(真的不能耽误)。在易于解析的语言的理想世界中,无需为解析的每个标记保持符号 table 最新。
在 x
的定义之后,=
发出初始化表达式的信号。这很容易解析:new
是一个明确的关键字,它不是一个位置 new
并且正在创建的类型就在那里。