书里以一个小程序开始,如下:
extern int x; //对外部定义的一个变量的引用
class test
{
public:
test(float, float, float);
//这里被传回和绑定的是按个x?
float test() const { return x; }
void test(float new_x) { new_x = x; }
private:
float x, y, z;
};
这个地方我刚看到时,首先想到的类中定义的float x,是基于局部变量屏蔽全局变量的原则,但仔细一想,又有些不对,因为类中对x的定义出现在函数后方,上面的局部变量屏蔽全局变量的原则是行不通的。然后又写程序测试了一遍,结果确实是类中的定义x,即外部的int x是被屏蔽了。
带个疑惑接着往下看时,书中说到了早期c++的两种防御编程风格。
一种是把数据成员的声明放在class的开头处,以确保正确的绑定,这里我觉得应该是类似于局部变量屏蔽全局变量的原则吧。
另一种是将成员函数(好像c++默认成员函数是inline的)的定义放到class的外头,类里只有其的声明,这也可以保证正确的绑定,因为这种方法中我看到函数的定义时,已经知道类中的数据成员。
接着根据这些提出了两个rules,大意应该是对成员函数的评估求值在整个类声明完成之后进行。这就很好解释了最开始的问题,对成员函数的data member的绑定发生类声明完成之后。
然而,书里接着说到一个问题还是让我有些惊讶。该规则对member function的参数列表并不起作用。参数列表中的名称还是会在第一次遭遇时会被适当的决议。因此extern和nested typed names之间的非直觉绑定还是会放生。见书中的这个例子:
typedef int length;
class test
{
public:
//这里函数me的参数列表val的类型是int,而不是float
void me(length val) { cout << sizeof(val) << endl; _val = val; }
length me() { return _val; }
private:
typedef float length;
length _val;
};
在vs2010下编译时,会有这样的警告:
1>d:\projects\test_for_inside_c++object\test_for_inside_c++object\1.cpp(35): warning C4244: “=”: 从“length”转换到“test::length”,可能丢失数据
1>d:\projects\test_for_inside_c++object\test_for_inside_c++object\1.cpp(36): warning C4244: “return”: 从“test::length”转换到“length”,可能丢失数据
这应该是说明了对参数列表中的类型判断是即时的,如果将typedef int length;注释掉则会显示语法错误。
如果将数据成员的声明放到类声明的开头,则上面的警告不会出现。
这里我又想到了一个问题,如果将member function的定义放到类外面,即类里只有其声明。会不会出现和类似将数据成员放到类开头这样的结果呢?代码如下:
typedef int length;
class test
{
public:
inline void me(length val);
inline length me() ;
private:
typedef float length;
length _val;
};
void test::me(length val) { cout << sizeof(val) << endl; _val = val; }
length test::me() { return _val; }
编译得到的结果另我很吃惊:
1>d:\projects\test_for_inside_c++object\test_for_inside_c++object\1.cpp(42): error C2511: “void test::me(test::length)”:“test”中没有找到重载的成员函数
1>d:\projects\test_for_inside_c++object\test_for_inside_c++object\1.cpp(33) : 参见“test”的声明
1>d:\projects\test_for_inside_c++object\test_for_inside_c++object\1.cpp(43): warning C4244: “return”: 从“test::length”转换到“length”,可能丢失数据
从编译的结果可以得出这样的结论,将member function的定义放到类外面,对结果不会有什么影响。即对参数列表中的判断是即时的,不会等到后期判断。我觉得可以从两个地方得出伤处结论:一是见这个warning:warning C4244: “return”: 从“test::length”转换到“length”,可能丢失数据,二是那个error,此例中将类外面定义的val当成float类型,类外面定义的me(length val)和类里定义的me(length val)将不是同一个函数了,他们的参数列表中参数的类型发生的变化,因此会匹配失败。
写到这里,真是感触良多,以前看到一些说法说是尽量将member function的定义放到类的外部,以及将数据成员的定义放到类的最后面,这好像是从类封装的角度说的,不过从这里看,好像也是有些关联。