您的位置:首页 > 编程语言 > C语言/C++

c++ 类作用域中的名字查找

2017-04-05 15:03 113 查看
一.类成员声明的名字查找 

按以下方式确定在类成员的声明中用到的名字  

什么叫做类成员声明的名字呢? 就是声明一个函数用到的类型。 比如  doube max(x, y) 其实double 就是类成员声明的名字。

* 先检查出现在名字使用之前的类成员声明,而这个之前是作用域内之前(1.全局作用域的之前;2.局部作用域的之前)

* 如果第一查找不成功,则检查包含类定义的作用域中出现的声明以及出现在类定义之前的声明.

例如:

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;
}
typedef long double Money;
Money bal;
上面的代码回报错,因为重复定义了Money.

二.在类成员定义中的名字查找

类定义的名字查找: 比如int pg; pg 就是类成员定义中的名字。
按以下方式确定在成员函数的函数体中用到的名字

* 首先检测成员函数局部作用域的声明

*如果在成员函数中找不到该名字的声明, 则检查对所有类成员的声明

*如果在类中找不到该名字的声明,则检查在此成员函数定义之前的作用域中出现的声明

例如:

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指针来使用它.

int fun(double pg)
{
return this->pg;
//return  A::pg;
}


函数作用域之后,在类作用域中查找

如果想要使用pg成员, 更好的方式是为形参取一个不同的名字:

int fun ( int b)
{
return pg;
}
现在编译器会在A类中查找该名字,尽管pg是现在fun中使用,然后在声明, 编译器还是确定这里用的是名为pg的数据成员. 所以用this指针和改变形参的名字都可以做到在类中查找。

类作用域之后,在外围作用域中查找:

如果编译器不能在函数或作用域中找到,就在外围作用域中查找.
上面的例子中, 在类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时用到的是哪个名字定义.如果存在错误,说明如何改正.

typedef string Type;
Type initVal();

class Exercise
{
public:
typedef double Type;
Type setVal( Type);//类声明的查找,type 指的是 double; 类定义的查找,这里type 指的是还是double
Type initVal(); //这里面类声明的查找type 也指的是double
private:
int val;
};

Type Exercise::setVal( Type parm) //;类声明的查找这里type指的是string, 类定义的查找 type指的是string,
{//为什么是string呢? 因为它仅仅查找函数只考虑它使用之前的声明,而这个之前是不仅仅是位置上的之前,也是作用
域的之前,这个type属于全局作用域的之前。
val = parm + initVal(); //这里initVal() 没有函数体
}


 在Exercise类的定义体内, 成员函数setVal和initVal的声明中作为形参类型和返回类型的Type所使用的都是Exercise内部定义的类型别名Type.
  在Exercise类的定义体之外成员函数setVal的定义中,
作为形参类型的Type,使用的是Exercise内部定义的类型别名Type,作为函数返回类型的Type,使用的是全局类型的Type.
在Exercise类的成员函数setVal的定义中使用的initVal,用到的是Exercise类的成员函数.

成员函数setVal的定义有错, 编译器会认为Exercise类中存在两个相互重载的成员函数setVal,但这两个函数的区别仅在于返回类型不同,不能构成合法的函数重载,因此有错,而且该汉化素应返回一个值, 可更正为

Exercise::Type Exercise::setVal( Type parm)
{
val=parm  + initVal();
retrun val;
}

注:形参表和函数体处于类作用域中,而函数返回类型不一定在类作用域中, 所以要在返回类型面前加上作用域运算符.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: