【问题标题】:Compiler: How is class instantiation code compiled?编译器:类实例化代码是如何编译的?
【发布时间】:2016-08-03 15:14:14
【问题描述】:

假设我们有(在 C++ 中):MyClass* x = new MyClass(10)

谁能解释一下当编译器解析这个语句时“究竟”发生了什么? (我试着看了一下红龙书,但找不到有用的东西。

我想知道堆栈/堆或编译器的符号表中发生了什么。编译器如何跟踪x 变量的类型?稍后对 x->method1(1,2) 的调用将如何解析为 MyClass 中的适当方法(为简单起见,假设没有继承,MyClass 是我们拥有的唯一类)。

【问题讨论】:

  • 请注意,Dragon Book 虽然深入研究了编译器,但并未考虑像现代 C++ 这样复杂的语言。特别是,由于模板编译 C++ 代码是图灵完备的。
  • 然而,Dragon Book 对编译器阶段确实有很好的解释。您对“堆栈/堆或编译器符号表中发生的情况”的怀疑表明您不了解这些阶段。堆栈/堆在代码生成过程中被认为是相当晚的,而符号表几乎存在于第一阶段(C++ 有一个带有自己的符号表的预处理器,但这与显示的声明无关)

标签: c++ compiler-construction runtime interpreter jit


【解决方案1】:

MyClass* x 是指向MyClass 类型对象(实例)的指针的定义。该变量的内存是根据其定义的位置分配的:如果它是在方法中定义的,并且是局部变量,则使用堆栈。并且是存储地址的内存。

然后表达式new MyClass(10) 是一个命令,用于在堆中为对象(实例)本身分配内存,并将返回地址存储在x 中。为了填充新对象MyClass(设置其初始状态)的内存,特殊方法(至少一个)会自动执行-构造函数(或在某些情况下是几个)-在您的示例中接收值10

因为 C++ 允许继承(这也是在创建实例时执行多个构造函数的原因),所以有一些机制可以确定应该准确调用哪个方法。您应该在某处阅读有关 Virtual method table 的信息。

在最简单的情况下(没有继承),变量x 的类型(指向MyClass 类型的对象的指针)提供有关对象结构的所有必要信息。因此,x->method1(1,2)(*x).method1(1,2) 提供成员method1 的调用,以使用参数12(存储在堆栈中)以及形成对象状态的数据(存储在堆中)和可通过类的任何非静态成员中的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);
}

【讨论】:

    【解决方案2】:

    C++ 确实有点讨厌,而且这已经在 C 中开始了。看看前 3 个标记:MyClass * x。编译器必须查找MyClass 以确定这不是乘法。既然是类型,也不应该去查找x,而是把x加到符号表就在那里(真的不能耽误)。在易于解析的语言的理想世界中,没有必要为每个解析的标记保持符号表的最新状态。

    x 的定义之后,= 发出初始化表达式的信号。这很容易解析:new 无疑是一个关键字,它不是一个展示位置 new 并且正在创建的类型就在那里。

    【讨论】:

      猜你喜欢
      • 2016-02-14
      • 2014-03-02
      • 2014-01-10
      • 2015-07-25
      • 1970-01-01
      • 1970-01-01
      • 2011-02-26
      • 2015-08-02
      • 2022-08-13
      相关资源
      最近更新 更多