文章目录
前言
跟上一篇介绍类内const成员定义一样,类内引用成员也具有要显示初始化的特性,所以定义的时候也有一些类似的细节需要注意。
一、类内引用成员
引用变量与普通变量的不同之处,其一就是引用变量必须要显示初始化,因为初始化后,引用变量一般就不能重新绑定到其他对象了,而普通变量可以默认初始化,之后也可以改变值,所以类内引用成员的定义也受到这种需要显示初始化特性的影响,容易出现以下几种错误定义。
二、错误定义
1.类未显示定义默认构造函数,且没有类内初始化器,那么使用默认构造函数会编译错误
代码如下(示例):
//类有一个引用成员,它没有类内初始化器,
//且类没有显示定义默认构造函数,则该类的默认构造函数被定义为删除的,
//因为默认的构造函数无法默认地初始化引用成员,所以无法合成默认的构造函数。
//如示例代码,我们无法定义MyClass的变量,因为构造函数已经删除
#if 1
class MyClass
{
public:
int &li_lv;
};
int main()
{
MyClass my_class; //错误,尝试引用已删除的函数
return 0;
}
#endif
输出如下(示例):
严重性 代码 说明 项目 文件 行 禁止显示状态
错误(活动) 无法引用 "MyClass" 的默认构造函数 -- 它是已删除的函数
错误 C2280 “MyClass::MyClass(void)”: 尝试引用已删除的函数
2.类显示定义构造函数,但不初始化引用成员,那么构造函数的定义会编译错误
代码如下(示例):
//类有一个引用成员,它没有类内初始化器,但是类显示定义了默认构造函数,
//却不初始化引用成员,此时默认构造函数报错,因为没有初始化引用成员
#if 1
class MyClass
{
public:
MyClass()
{
}
int & li_lv_;
};
int main()
{
MyClass my_class;
return 0;
}
#endif
编译输出如下(示例):
严重性 代码 说明 项目 文件 行 禁止显示状态
错误(活动) "MyClass::MyClass()" 未提供初始值设定项
错误 C2530 “MyClass::li_lv_”: 必须初始化引用
三、正确定义
1.使用类内初始化器
不过一般很少使用这种方式初始化类内引用成员,因为可能涉及到全局变量的定义,而全局变量用得偏少。
代码如下(示例):
//类有一个引用成员,使用类内初始化器初始化
#if 1
int g_li_lv = 0;
class MyClass
{
public:
int &li_lv_ = g_li_lv;
};
int main()
{
MyClass my_class;
cout << my_class.li_lv_ << endl;
cout << &my_class.li_lv_ << endl;
cout << &g_li_lv << endl;
system("pause");
return 0;
}
#endif
程序输出如下(示例):
0
001CB148
001CB148
请按任意键继续. . .
2.使用构造函数初始化列表
代码如下(示例):
//类有一个引用成员,使用构造函数初始化列表初始化
#if 1
class MyClass
{
public:
MyClass(int & li_lv) :li_lv_(li_lv)
{
}
int &li_lv_;
};
int main()
{
int li_lv = 0;
MyClass my_class(li_lv);
cout << my_class.li_lv_ << endl;
cout << &my_class.li_lv_ << endl;
cout << &li_lv << endl;
system("pause");
return 0;
}
#endif
程序输出如下(示例):
0
0038F820
0038F820
请按任意键继续. . .
总结
总之我们对于类内引用成员也要跟类外引用变量、类内const变量一样注意初始化,而且类内错误的定义更隐藏,可能编译起来没问题,直到用到了对应的构造函数才会出现问题。对于类内引用的初始化,一般首选初始化列表初始化。