1.在了解类定义中,名字的查找规则之前,我们先来了解下普通的名字查找规则
- 当前作用域中查找,只考虑在名字使用之前出现的声明
- 外层作用域中查找
- 没找到,报错
代码示例:
void PrintValue(){
printf("%d\n",a); // 这里会报错,因为a的定义出现在函数的后面
}
int a = 100;
int main( void ){
PrintValue();
return 0;
}
int a = 100;
void PrintValue(){
printf("%d\n",a); // 这里不会报错
}
int main( void ){
PrintValue();
return 0;
}
2.类中使用的名字查找规则
2.1首先我们需要先了解编译器对类定义的处理逻辑:
- 首先,编译成员的声明(这一步中名字的查找规则和上面讲的普通的名字查找规则一样)
- 直到类全部可见后,才会编译函数体
类中的所有声明包括:类型名(使用typedef,using声明定义的类型名),成员函数的返回类型和形参列表中的类型名,数据成员的类型名
这里举个例子让大家有一个直观的感受
class CD{
public:
...
int GetValue() const{
return a; // 如果这里还使用普通的名字查找规则,那么会先处理函数体中的变量a,此时变量a还没有出现
}
private:
int a = 100;
};
上述代码编译的时候没有报错,说明在编译过程中,GetValue函数,找到了在它下面定义的成员变量a。
2.2类定义中的 类型名要特殊处理
一般来说,内层作用域可以重新定义外层作用域中的名字,即使该名字已经在内层作用域中使用过。
#include <iostream>
using namespace std;
typedef doubel Money;
int main( void ){
Money a; // a是doubel类型
typedef int Money;
Money b; // b是int类型
return 0;
}
上述代码编译成功。
但是在类中,如果成员使用了外层作用域中的某个名字,而该名字代表一种类型,则类不能在之后从新定义该名字。
实例代码:
typedef double Money;
class Account{
public:
Money balance(){
return bal;
}
private:
using Money = double;
// typedef int Money;
Money bal;
};
上面的代码在编译的时候会报错!!!
为什么会报错呐?如果不报错,由于编译器对类的定义分2步处理,成员函数balance的返回类型Money是外层作用域中定义的double类型,而成员函数balance函数体中的返回值bal的类型,是类内部定义double类型,假如我们将类内部定义的Money类型设置为int,此时成员函数balance的返回类型就不一致了。
类型名的定义通常出现在类的开始处,这样就能确保,所有使用该类型的成员,都出现在类型名的定义中。
下面是类型名正确的用法:
typedef double Money;
class Account{
public:
using Money = double;
// typedef double Money;
Money balance(){
return bal;
}
private:
Money bal;
};
2.3成员函数中名字的查找规则(函数体中使用的名字)
这里还分为两种情况
2.3.1成员函数定义在类的内部(内联的成员函数)
- 函数体内部,名字使用之前的范围内查找
- 如果没有在函数体中找到,在类内继续查找,此时类的所有成员都可以被考虑
- 如果在类中也没找到,在类定义之前的外层作用域中查找
- 没有找到,报错
2.3.2成员函数定义在类的外部
- 函数体内部,名字使用之前的范围内查找
- 如果没有在函数体中找到,在类内继续查找,此时类的所有成员都可以被考虑
- 如果在类中也没找到,则在成员函数定义之前的作用域中查找(这里也包含了类定义之前的作用域了)
- 没有找到,报错
class Screen{
public:
typedef std::string::size_type pos;
void setHeight( pos );
pos height = 0;
};
Screen::pos verify( Screen::pos );
void Screen::setHeight( pos var ){
height = verify( var );
}
上述代码中:全局函数verify的声明在Screen类的定义之前是不可见的。然而,对于定义在类外部的成员函数来说,可以在成员函数定义之前的作用域中查找!!!所以这里依然可以找到。
总结:在类中的名字查找,主要是成员函数函数体中名字的查找,根据成员函数的定义位置,名字的查找规则稍微有点区别。