关于编译/链接过程有很多参考,但我对一个更具体的问题感兴趣:编译一个类。
问题出现了,因为一般来说,在使用之前必须先知道事情。例如:如果以前没有声明过函数,则无法调用该函数。
在课堂上,它不是以同样的方式完成的。您可以在成员出现之前使用该成员。编译器做什么?标准是否说明了前一阶段的编译?
更具体地说,以下示例显示了我们如何使用下面定义的成员。
#include <iostream>
class EvenOdd {
public:
EvenOdd(): value(0) {}
void assignEven(unsigned v) {
if (v>0 && v%2==1) {
std::cout << "Wrong call... is odd" << std::endl;
assignOdd(v);
}
else {
std::cout << "Right..." << v << " is Even" << std::endl;
value= v;
}
}
void assignOdd(unsigned v) {
if (v>0 && v%2==0) {
std::cout << "Wrong call... is even" << std::endl;
assignEven(v);
}
else {
std::cout << "Right..." << v << " is Odd" << std::endl;
value= v;
}
}
private:
unsigned value;
};
int main()
{
EvenOdd a;
std::cout << "Do it right..." << std::endl;
a.assignEven(2);
std::cout << "doing it wrong..." << std::endl;
a.assignEven(3);
}
我们还可以添加关于内联函数的更多问题,可以在调用点之后定义,编译器可以毫无问题地解决。我猜答案是相关的。
更新:我知道编译/链接有几个步骤。另一方面,如果编译器接受调用定义的函数,那么编译器在某种意义上已经分析了代码。问题是¿之前做过哪种前一阶段?此外......我们在标准的哪一部分找到了与使用成员定义相关的东西?
要知道编译器的工作方式非常有趣,因为它必须知道有关函数的详细信息(至少是标题),它似乎与编译实际对应。甚至数据成员也必须编译,因为你必须在上面函数的上下文中关联它的类型
它的工作方式类似于重新排序的代码,但它与上面的示例不一致,因为两个函数成员互相调用。这就像重新排序数据成员和函数头可能是编译器考虑的代码。
答案 0 :(得分:7)
标准说
在类说明符的结束
}
,类被视为完全定义的对象类型(3.9)(或完整类型)。在类成员规范中,该类在函数体,缺省参数,异常规范和默认成员初始化器(包括嵌套类中的这些东西)中被视为完整。否则,它在其自己的类成员规范中被视为不完整。
这尤其意味着成员函数体可以引用在其下面声明的类成员。该标准并不关心实现如何实现这一点。一种可能的方法是推迟成员函数体和上面指定的其他元素的语义分析,直到看到类的右括号。
答案 1 :(得分:0)
类中的函数可以访问和修改(除非函数是常量)数据成员而不声明它们,因为数据成员已经在类中声明。在你的回答为什么函数不需要在课堂上声明。