一.类成员声明的名字查找
按以下方式确定在类成员的声明中用到的名字
* 检查出现在名字使用之前的类成员声明
* 如果第一不查找不成功,则检查包含类定义的作用域中出现的声明以及出现在类定义之前的声明.
例如:
typedef double Money;
class Account
{
public:
Money balance() { return bal;}
private:
Money bal;
};
在处理balance函数的声明时,编译器首先在类Account中查找Money的声明,编译器只考虑出现在Moeny使用之前的声明,因为找不到任何成员声明,编译器随后在全局作用域中查找Money的声明.找到了Money的声明,并将它用作balance()函数的返回类型 和 数据成员bal的类型.
通常,名字必须在使用之前进行定义. 而且,如果一个名字被用作类型名, 该名字就不能重复定义:
typedef double Money;
class Account
{
public:
Money balance() { return bal;}
<span style="font-family: Arial, Helvetica, sans-serif;"> typedef long double Money;</span>
Money bal;
};
上面的代码回报错,因为重复定义了Money.
二.在类成员定义中的名字查找
按以下方式确定在成员函数的函数体中用到的名字
* 首先检测成员函数局部作用域的声明
*如果在成员函数中找不到该名字的声明, 则检查对所有类成员的声明
*如果在类中找不到该名字的声明,则检查在此成员函数定义之前的作用域中出现的声明
例如:
const int pg=10;
class A
{
public:
int fun(int pg)
{
return pg; //哪个pg?
}
private:
int pg;
};
上面的代码中fun()函数内return 的pg是哪个pg呢? 可以测试一下
int main()
{
int x;
A test;
x=test.fun(3);
cout<<x<<endl;
return 0;
}
运行结果是三,说明函数fun()返回的是形参声明的那个pg.
查找fun的定义中使用的名字pg时, 编译器首先在该函数的局部作用域中查找. 函数局部作用域中声明了一个函数形参.查找成功, 形参pg会屏蔽名为pg的成员.
尽管类的成员被屏蔽了,仍然可以通过类名来限定成员名或显示使用this指针来使用它.
把fun代码修改如下:
int fun(double pg)
{
return this->pg;
//return A::pg;
}
函数作用域之后,在类作用域中查找
如果想要使用pg成员, 更好的方式是为形参取一个不同的名字
int fun ( int b)
{
return pg;
}
现在编译器会在A类中查找该名字, 尽管pg是现在fun中使用,然后在声明, 编译器还是确定这里用的是名为pg的数据成员.
类作用域之后,在外围作用域中查找
如果编译器不能在函数或作用域中找到,就在外围作用域中查找. 上面的例子中, 在类A定义之前的全局作用域中声明了一个名为pg的全局对象, 然后, 它被屏蔽了..
尽管全局对象被屏蔽了,但通过全局作用域确定操作符来限定名字,仍然可以使用它.
#include <iostream>
using namespace std;
const int pg=10;
class A
{
public:
int fun(double pg)
{
return ::pg; //这里使用全局作用域
}
A() : pg(0) { };
private:
double pg;
};
int main()
{
int x;
A test;
x=test.fun(3);
cout<<x<<endl;
return 0;
}
运行结果为10.
最后用课后习题总结一下:
解释下述代码.指出每次使用Type或initVal时用到的是哪个名字定义.如果存在错误,说明如何改正.