1、问题的引入
1).观察以下第一块代码:
#include <iostream> using namespace std; class Screen{ public: void test(){ dummy_fcn( ); } void dummy_fcn( ){ } };
此代码编译无错误。。。。。。。。。。。。。。。
2).再看以下第二块代码:
#include <iostream> using namespace std; void test(){ dummy_fcn( ); } void dummy_fcn( ){ }
此代码编译出错。。。。。。。。。。。。。
3).再看第三块代码:
#include <iostream> using namespace std; void dummy_fcn( ){ } void test(){ dummy_fcn( ); }
此代码编译也无错误。。。。。
4).第四块代码:
#include <iostream> using namespace std; class Screen{ public: typedef std::string::size_type index; void test(){ dummy_fcn( ); } void dummy_fcn( ){ cursor = width * height; } private: index cursor; index height, width; };
此代码编译并无错误。。。。。。。。。。。。。。。。。。。。。。
5).第五块代码:
#include <iostream> using namespace std; class Screen{ public: void test(){ dummy_fcn( ); } void dummy_fcn( ){ cursor = width * height; } private: index cursor; index height, width; typedef std::string::size_type index; };
此代码编译出错。。。。。。。。。。。
2、发现
发现1:对比第1、2、3块代码,我们发现在类中,名字查找是比较特殊的。对于普通的函数名字,编译器只会从其之前的地方查找是否声明,若无声明就报错(如代码2)。。而对于类中的名字来说,编译器将会在整个类作用域中进行查找(如代码1),若找不到,会进一步在整个类的定义之前进行查找。
发现2:对比第4、5块代码,其不同之处仅仅在于index类型变量的定义位置。可知,编译器在对类的定义进行编译时,并不会在整个类作用域内查找类型的定义(此例中index的定义)。
3、思考
以上的两点发现其实和类定义的“两步编译”有关。。见《C++ primer》第4版中P382,
“类定义实际上是在两个阶段中处理的:
(1)首先,编译成员声明;
(2)只有在所有成员出现之后,才编译它们的定义本身。
”
其中发现2对应“两步编译”中的第一步(《C++ primer》中称为类成员声明的名字查找),而发现1对应第二步(《C++ primer》中称为类成员定义中的名字查找)。
3.1第一步编译的思考
在第一步编译所有成员声明中,不会检查成员函数定义中的函数调用(如发现2中的例子)。此时只会对成员声明中的类名是否定义进行检查(如上例中的index),这种检查会分为两步:
1)在类中该类名使用之前进行查找
2)在整个类定义之前进行查找
3.2第二步编译的思考
在第二步编译它们的定义时,会进一步检查成员函数中的函数调用(如发现1中的例子)。此时的检查会分为三步:
1)在成员函数局部作用域中进行查找
2)在整个类定义域中进行查找。之所以能够在整个类定义域中进行查找,是因为经过了第一步的对所有类成员声明的定义。这也是和普通名字查找不同的地方(如发现1中的例子)
3)在这个类成员函数定义之前(这里不仅仅指类定义之前,因为类成员函数可能是在类外部)进行查找