C++ 声明的编译顺序
C++ compilation order of declarations
我对以下代码感到困惑:
#include <iostream>
class foo
{
public:
foo(int _i)
{
this->i = _i;
}
void print()
{
std::cout << i << std::endl;
}
private:
int i;
};
int main()
{
foo f(5);
f.print();
}
这是如何编译的?整数 'i' 在 constructor/print 方法中使用后声明,但代码已成功编译。我的理解是 C++ AST 是在解析文件时生成的;因为 C++ 编译器应该提前 1 个标记,所以我们不应该知道 'i' 是一个有效成员,直到解析器远远超过 1 个标记。我这里显然有误会。
编译器是如何编译的?它是否只是跳过函数定义,然后再解析它们?
解析 C++ 是一项比“先看一个标记”所概括的任务复杂得多的任务。有许多有效的 C++ 构造需要任意前瞻(或回溯,这实际上是同一件事)。
但这不是这里的问题。
编译器可以在不知道 i
解析到什么的情况下生成 AST。从词法结构可以清楚地看出 i
是一个标识符。编译器只需要知道它是否标识了一个对象(或函数)。如果名称标识类型,那将影响解析。
C++ 允许 class 成员以任何顺序声明,但必须始终明确名称是否为类型。命名类型的成员必须在使用前声明。如果重新声明不是类型成员,则必须在使用前重新声明在外部作用域中标识类型的名称。
因此编译器可以假定未声明的标识符命名对象而不是类型,并且当前是类型的名称将继续是类型。它命名的对象或类型可以稍后确定,通常在 class 声明的末尾。
声明为模板的名称也有类似的要求。
C++ 中的名称解析非常复杂。但它(大部分)是语义。除了类型和对象位于同一个命名空间这一事实之外,名称解析不会影响解析。 (当然,如果在函数调用语法中使用了名称,但结果证明它不是成员函数,那就是错误,就像使用了不正确参数的函数名称一样。但这不是 语法 错误。)
我对以下代码感到困惑:
#include <iostream>
class foo
{
public:
foo(int _i)
{
this->i = _i;
}
void print()
{
std::cout << i << std::endl;
}
private:
int i;
};
int main()
{
foo f(5);
f.print();
}
这是如何编译的?整数 'i' 在 constructor/print 方法中使用后声明,但代码已成功编译。我的理解是 C++ AST 是在解析文件时生成的;因为 C++ 编译器应该提前 1 个标记,所以我们不应该知道 'i' 是一个有效成员,直到解析器远远超过 1 个标记。我这里显然有误会。
编译器是如何编译的?它是否只是跳过函数定义,然后再解析它们?
解析 C++ 是一项比“先看一个标记”所概括的任务复杂得多的任务。有许多有效的 C++ 构造需要任意前瞻(或回溯,这实际上是同一件事)。
但这不是这里的问题。
编译器可以在不知道 i
解析到什么的情况下生成 AST。从词法结构可以清楚地看出 i
是一个标识符。编译器只需要知道它是否标识了一个对象(或函数)。如果名称标识类型,那将影响解析。
C++ 允许 class 成员以任何顺序声明,但必须始终明确名称是否为类型。命名类型的成员必须在使用前声明。如果重新声明不是类型成员,则必须在使用前重新声明在外部作用域中标识类型的名称。
因此编译器可以假定未声明的标识符命名对象而不是类型,并且当前是类型的名称将继续是类型。它命名的对象或类型可以稍后确定,通常在 class 声明的末尾。
声明为模板的名称也有类似的要求。
C++ 中的名称解析非常复杂。但它(大部分)是语义。除了类型和对象位于同一个命名空间这一事实之外,名称解析不会影响解析。 (当然,如果在函数调用语法中使用了名称,但结果证明它不是成员函数,那就是错误,就像使用了不正确参数的函数名称一样。但这不是 语法 错误。)