C++ Primer学习笔记——类中名字查找

类中名字查找


在目前为止,我们编写的程序中,名字查找的过程比较直接了当:

  • 首先,在名字所在的块中寻找其声明语句,只考虑在名字使用之前出现的声明
  • 如果没找到,继续查找外层的作用域
  • 如果最终没有找到匹配的声明,则程序报错。

对于定义在类内部的成员函数来说,解析其中名字的方式与上述查找规则有所区别。类的定义分两步处理:

  • 首先,编译成员的声明
  • 直到类全部可见后才编译函数体

上面是 C++ Primer 关于名字查找的叙述。下面直接举例说明。

1、 类成员函数声明与定义在一起

	typedef string db;
	string ball;
	
	void fin() {
		cout << "类外函数" << endl;
	}
	
	class A {
	public:
		db test0(db a) {//此处的db是string类型
			//cout << "test1: " << typeid(test1) << endl;
			fin();
			ball = 123;
			return a;
		}
		void fin() {
			cout << "类内函数" << endl;
		}
	public:
		typedef double db;
		db test1;
		double ball;
	};

对于类 A ,编译器首先依次编译成员函数 test0,fin 的声明、一条typedef 重命名以及两个成员变量 test1 以及 ball 的声明。
对于 test0,看其返回类型以及形参列表,两者都为 db,在这里可见的 db 只有类外那条 string 的重命名语句,类内的 double 重命名语句,由于编译器还没处理到那里,因此在这是不可见的,所以,此处的 db 均为 string 类型。假如将类外的 string 的重命名语句注释掉,在此处会报错,因为找不到关于 db 的声明。
处理完 test0 的声明后,再处理 fin 函数的声明,这里没啥可说的,唯一注意的就是在这里 fin 函数将类外的 fin 函数覆盖了。再往下,编译器发现了另一条关于 db 的重命名语句。在这里,有必要注意的是,尽管重新定义类型名字是一种错误的行为,但是编译器并不为此负责,一些编译器仍会顺利通过这样的代码,而忽略代码有错的事实。对于这条语句,笔者的编译器并未报错,也就是在从此处开始,db 变成了 double 类型的别名,而不是 string 类型的别名
继续往下,test1 的类型为 db,即为 double,而不是像 test0 那里的string。再往下,是 ball 的声明。此处的 ball,将类外声明的 ball 给覆盖了。之后类内使用的 ball 都是指类成员变量,若想使用类外的 ball,则要加上作用域运算符,即 ::ball。
处理完声明,就开始编译成员函数的函数体了。首先是 test0 的函数体,此处的 fin() 是类成员函数,此处的 ball 是类成员变量。然后编译 fin 的函数体,这也没啥好说的。

2、 类成员函数声明与定义分开

下面考虑类成员函数的声明与定义分开的情况。直接看下面的代码。

	typedef string db;
	string ball;
	
	void fin() {
		cout << "类外函数" << endl;
	}
	class A {
	public:
		db test0(db a);
		void fin();
	public:
		typedef double db;
		db test1;
		double ball;
	};
	db A::test0(db a) {
		//这里的db是类内的double类型,因为此处是函数的定义,声明部分编译器已经进行完了
		//想变成string类型的话得  ::db A::test0(::db a)
		fin();
		ball = 123;
		return to_string(ball);
	}
	void A::fin() {
		cout << "类内函数" << endl;
	}

这里的代码和第一块代码看上去没啥不同(咱们先忽略注释哈,手写版滑稽)。可是,根据本文最开始那段摘自 C++ Primer 的叙述,就会出现非常尴尬的局面。当处理完类的声明部分时,编译器开始处理类外定义的类成员函数。
首先是 test0,此处的 test0 的形参类型和返回值类型都是 db,此处的 db 是 double 的别名,因为在声明部分,已经对 db 重新 typedef 了。于是在类内的声明中 test0 的形参和返回值类型都应是 string 类型,结果却找不到该函数的定义。在类外定义的 test0 却没有其对应的声明。为了化解这种尴尬的局面,第一种方法如注释里说的,用作用域运算符表明此处的 db 是类外声明的 db,第二种方法就是在类外 test0 的定义出将返回值和形参类型都写成 string 类型。当然最好的方法还是避免出现重新定义类型名字的行为,毕竟,这在某种程度上算是一种错误,虽然编译器并不报错。其它的也就没什么了,fin 是类成员函数,ball 是类成员变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值