[cpp primer随笔] 17. 类中名字的查找机制

我发现写文章的逻辑真的很重要。如果只是简单的陈述知识点,那么阅读的体验会很糟糕。要想做到文章逻辑清晰,文笔是其次,作为作者首先就要对这个问题有比较顺畅的思路,绕后再把内容呈现出来。话不多说,开始本篇的内容。

本篇主要介绍了C++中类中名字的查找机制。

名字查找(name lookup)指的是解析一个程序中出现的名字,并且寻找到与之相匹配的声明,这是在程序的编译阶段完成的。

对于一个类外的普通名字,例如一个类型名或一个变量名,其名字查找过程比较直接。编译器会先在当前作用域内、该名字使用之前的部分查找有无该名字的声明,若无,则会去外层作用域寻找依次类推。如果最终没有找到该名字的有效声明,则判定为这是一个未定义的名字。

然而,类中名字的查找方式与方才所描述的有所不同。因为一个类定义的代码是分为两部分来编译的编译器会先编译类成员声明,再编译类内成员函数的代码块(无论成员函数的定义在类内还是类外)。

1. 类声明中的名字查找

类声明中需要进行查找的名字,包括成员函数声明中的返回类型与形参类型名,以及成员变量中的类型名。这种名字大体可以分为两种,一种是自定义类型名,另一种是类型别名。

在名字查找时,会先使用该名字的当前声明语句,在类定义内,之前是否出现过该名字的声明。若无,会在外层作用域该类定义之前的部分查找,依次类推向外拓展,直至找到匹配的声明,该名字解析成功。否则,这是一个未声明的名字。

下面是一个例子:

class NAME;   // 外层作用域1

class People{ // 作用域People,类内作用域
private:
	using MONEY = double;
	MARRIED isMarried = false; // 4. 错误,未声明的名字MARRIED
public:
	People(NAME name);   // 1. 正确
	People(AGE age);     // 2. 错误,未声明的名字AGE
	People(MONEY money); // 3. 正确
	typedef bool MARRIED;
};
// 外层作用域1,但是在类定义(使用该名字的位置)之后
using AGE = int;

上面的例子中描述了4种情况。

  • 情况1:首先我们定义了一个类People。在第一个构造函数的形参列表中,我们使用了自定义类型NAMENAME的声明虽然不在类内,但是位于People类定义所处作用域外层作用域1的前面,因此类内的名字NAME解析成功。
  • 情况2:首先类内没有,AGE是在People类定义之后定义的一个类型别名,因此解析失败。
  • 情况3:MONEY是在第三个构造函数声明之前,定义的一个类型别名,因此查找成功。
  • 情况4:isMarried是一个类型为MARRIED的成员变量。因为MARRIED本身是一个定义在该成员变量之后的一个类型别名,因此类内查找失败,外层作用域又没有MARRIED的声明,因此该名字解析失败。

此外,需要注意类中类型成员的特殊性:尽管内层作用域中对名字重新声明可以覆盖外层作用域,但是类外定义的类型别名,在成员声明中一经使用,之后的声明禁止重新定义该别名。哪怕重新声明前后,该别名表示的类型相同。(编译器不会检查这种错误,但是前后两次MONEY的类型取决于哪个,C++标准并未指定,这属于编译器具体实现问题)下面是一个例子:

using MONEY = double;
class People{ // 作用域People,类内作用域
private:
public:
	People(MONEY money);
	using MONEY = double; // 不推荐这么做
};

尽量将类型成员的声明放在类定义的一开始,有利于代码语义清晰。

2. 成员函数代码块中的名字查找

成员函数代码体的编译是在成员声明编译之后,因此无论成员函数的定义在类内与类外,均可以使用类成员声明中的所有名字

成员函数定义在类内的,其名字查找机制与成员声明相同。

成员函数定义在类外的,若函数体中出现类定义中没有声明过的名字,则会在成员函数定义所在作用域进行名字查找。与类中成员声明一样,仅在成员函数定义前声明的名字可以被成功搜寻,之后的依旧无效。当前作用域若查找失败,则会向外层作用域依次扩大搜寻范围,直至找到或者判定为名字未定义。(最大找到全局作用域)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值