C++ 类成员函数作用域以及构造函数初始值列表

名字查找与类的作用域:

普通查找方式:

  1. 在名字所在的块中寻找声明,只考虑在语句之前的声明
  2. 如果没找到继续查找外层作用域,也是语句之前的声明
  3. 如果没找到,程序报错

定义在类内部的成员函数

  1. 首先编译成员的声明(声明中的名字,函数返回类型和参数列表)
  2. 直到类全部可见后编译函数体

成员函数中的名字按下面的方式解析

  1. 在成员函数内查找该名字的声明,只有使用之前出现的声明 才被考虑
  2. 如果在成员函数内没有找到,在类中继续查找,这时类中所有的成员都被考虑
  3. 如果类中也没有找到,在成员函数定义之前的作用域内继续查找

注意:一般来说内层作用域可以重新定义外层作用域的名字,但是在类中如果出现外层作用域的名字,而该名字代表一种类型,那么这个名字不可以被重新定义

构造函数初始值列表

我们定义变量时习惯于立即对他初始化,而非先定义、再赋值

string fo = "hello world!";	//定义并初始化
string bar;
bar = "hello world!";	// 先定义再初始化

就对象的数据成员而言,初始化与赋值也有类似的区别。如果没有在构造函数的初始值列表中显示的初始化成员,该成员将在构造函数体执行之前执行默认初始化,例如:

class Sales
{
	private	:
		int i;
		string s;
	public:
		Sales(int ii, string ss)
		{
			i = ii;
			s = ss;
		}	
}

上面类的成员i和s在执行构造函数之前,已经执行过默认初始化,相当于先初始化再赋值。再看下一个例子:

class Sales
{
	private	:
		const int i;
		string s;
	public:
		Sales(int ii, string ss)
		{
			i = ii;	//报错,i是常量不可被修改
			s = ss;
		}	
}

当 i 变为常量成员时,上述代码就会报错,所以必须使用构造函数初始值列表

class Sales
{
	private	:
		const int i;
		const int j;
	public:
		Sales(int ii, int jj) : i(ii), j(jj){};
}

注意一点: 初始化的顺序与成员在类中定义的顺序一致,也就是第一个成员先被初始化,然后第二个…,例如

class Sales
{
	private	:
		const int i;
		const int j;
	public:
		//未定义的,i在j之前被初始化
		Sales(int val) : j(val), i(j){};
}

上面的代码看似没有问题,先用 val 初始化 j,然后用 j 初始化 i;但是因为 i 先被定义,所以先执行 i 的初始化,但此时 j 还未定义值。

猜你喜欢

转载自blog.csdn.net/adventural/article/details/88067757