C++ 类的作用域
在类的作用域之外,普通的数据和函数成员只能由对象、引用或者指针使用成员访问运算符访问,对于类类型成员,则使用作用域访问运算符。
作用域和定在类外部的成员
例如我们定义Window_mgr类的clear成员
因为编译器在参数列表之前已经明确了我们当前正位于Window_mgr类的作用域之中,所以不必再专门说明ScreenIndex是Window_mgr类定义的,screens同理。
另一方面,函数的返回类型通常出现在函数名之前,因此当成员函数定义在类的外部时,返回类型中使用的名字都位于作用域之外,这是返回类型必须指明他是哪个类的成员
例如:
名字查找与类的作用域
在我们编写的程序中名字查找的过程比较直截了当
1在名字所在的块中寻找其声明语句,只考虑在名字使用之前出现的声明
2如果没找到继续查找外层作用域
3如果最终没有找到声明,报错
对于定义在类中的成员函数来说,解析其中名字的方式和上面有区别
1编译成员声明
2直到类全部可见后才编译函数体
用于类成员声明的名字查找
这种两阶段的处理方式只适用于成员函数中使用的名字,声明中使用的名字包括返回类型或参数列表中使用的名字,都必须在使用前确保可见,如果某个成员的声明使用了类中没有出现的名字,则编译器将会在定义该类的作用域中继续查找。
当编译器看到balance的声明时,他将在Account类中查找对Money的声明,编译器只考虑Account中使用Money前出现的声明,因为没有找到匹配,所以编译器会接着到Account的外层作用域中查找。这个例子中,编译器会找到Money的typedef语句,该类型被用作balance函数的返回类型,以及数据成员bal的类型,另一方面因为balance函数只有在整个类可见后才被处理,所以return返回的是名为bal的成员不是string对象。
类型名要特殊处理
一般来说内层作用域可以重定义外层作用域中的名字,即使该名字已经在内层使用过,然而在类中,如果成员使用了外层作用域的某个名字,而该名字代表一种类型,则类不能再之后重新定义该名字。
即使Account中定义的Money类型和外层一致,上述代码依旧是错误的。
注意:重新定义类型名字是一种错误的行为,但是编译器并不为此负责,一些编译器还是可以通过这样的代码。
注意:类型名的定义通常出现在类的开始处,这样就能确保所有使用该类型的成员都出现在定义之后。
成员定义的普通块作用域的名字查找
解析成员函数中使用的名字
1在成员函数内查找该名字的声明,只有在函数使用之前出现的声明才被考虑
2如果在成员函数内没有找到,则在类内继续查找,这时类的所有成员都可以被考虑。
3如果类内没有找到声明,在成员函数定义之前的作用域内继续查找
一般来说不要使用成员的名字作为某个成员函数的参数!
处理cursor时,他首先在函数作用域内查找表达式中用到的名字,函数的参数位于作用域中,因此用到的height使用的是参数height。
例子中,height参数隐藏了同名的成员
并不建议使用上述代码,如果参数使用其他名字是最好的方法。另一方面即使成员函数内隐藏了成员height但是我们可以强行访问它。
类作用域之后,在外围的作用域中查找
如果我们需要外层作用域的height
在文件中名字的出现对其进行解析
成员定义在类的外部时,名字查找的第三步不仅要考虑类定义之前的全局作用域中的声明,还要考虑在成员函数定义之前的全局作用域中的声明。
verify的声明在Screen类的定义之前是不可见的,然而名字查找的第三步包括了成员函数出现之前的全局作用域,因为verify的声明位于setHeight的定义之前,所以可以被正常使用。