栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++关键字系列【二】:mutable、explicit

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++关键字系列【二】:mutable、explicit

目录
  • mutable
    • 作用
    • 注意事项
    • 代码示例
      • 例1
      • 例2
  • explicit
    • 作用
    • 注意事项
    • 代码示例

mutable

mutable的中文意思是可变的,刚好是const的反义词。被mutable修饰的变量永远都是可变的,即使在可以const成员函数内,其依然可变。

作用
  • 保持常量对象大部分数据成员只读的情况下,对个别数据成员进行修改
  • 使类的const成员函数能够修改对象的mutable数据成员
  • 可变lambada,默认情况下,对于一个值拷贝的变量,lambda不会改变其值,但如果我们希望能改变一个被捕获的变量的值,就必须在参数列表首加上mutable
注意事项
  • mutable只能用来修饰类的非静态和非常量数据成员,即非static和非const

mutable不能修饰const数据成员,这非常容易理解,毕竟mutable是其反义词,同时修饰那自相矛盾了
mutable不能修饰static数据成员,是因为static数据成员不属于某个类对象,而是被类中所有对象共享,即属于类,const类对象和const函数都可以对其修改,并不需要加上mutable

  • 除非十分必要,在一个类中尽量不要使用mutable,大量使用mutable说明该类设计上有缺陷
代码示例 例1
class A {
public:
	static int num;
	void GetCallTimes()const {
		cout << "count:" << count++ << endl;
	}
	void GetNum()const {
		num = 15;
		cout << "num:" << num << endl;
	}
private:
	//int count = 0;错误,不能在const函数中修改变量count
	//mutable const int count = 0;编译出错
	//mutable static int count = 0;编译出错
	mutable int count=0;
};
int A::num = 0;
int main(void)
{
	A a;
	const A b;
	for (int i = 0; i < 5; i++) {
		a.GetCallTimes();
	}
	b.num = 10;//常量对象可以修改类的静态数据成员
	cout << "num:" << A::num << endl;
	b.GetNum();
}

输出结果:

例2
int main(void)
{
	int num = 10;
	//f可以改变它所捕获的变量的值
	auto f = [num]()mutable {return ++num; };//如果不加mutable,则++num会出现编译错误
	num = 5;
	auto j = f();//j为11
}

lambda的值捕获类似参数传递,不过其捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝,所以在num=5后,并不会影响到lambda内对应的值,即j为11,而不是6

explicit 作用

在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数,不能发生相应的隐式类类型转换,只能以显示的方式进行类类型转换。即被explicit修饰的构造函数不能再通过该构造函数隐式的创建类对象

原则上应该在所有的构造函数前加explicit关键字,除非明确需要用隐式转换的时候再去解除explicit,这样可以大大减少错误的发生。

注意事项
  • 只能用于类内声明的构造函数
//错误:explicit关键字只允许出现在类内的构造函数声明处
explicit A::A(double d){
	```
}
  • 只对一个实参的构造函数有效,或者有n个参数,但是其中 n-1 个参数是带有默认值的构造函数也有效
  • explicit构造函数只能用于直接初始化
代码示例

未加explicit的隐式类类型转换

class A {
public:
	A() = default;
	A(double d) {
		this->d = d;
		cout << "A(double d)" << " d:" << d << endl;
	}
	A(int x, double d=2.5) {
		this->x = x;
		this->d = d;
		cout << "A(int x, double d=2.5)" << " x:" << x << " d:" << d << endl;
	}
	A(const A&a) {
		d = a.d;
		x = a.x;
		cout << "A(const A&a)" << endl;
	}
	void func(const A& a) {
		cout << "void func(const A& a)" << " x:" << a.x << " d:" << a.d << endl;
	}
	~A() {
		cout << "~A()" << endl;
	}
private:
	double d = 0;
	int x = 0;
};

int main(void)
{
	//隐式转换过程如下
	//tmp = A()  
	//A a1(tmp);  
	//tmp.~A(); 
	A a1 = 1.5;
	//隐式调用A(int x, double d=2.5)构造函数,虽然有2个参数,但后一个有默认值,仍然能发生隐式转换, 
	A a2 = 1;
	//隐式调用A(const A&a)拷贝构造函数
	A a3 = a1;
	//隐式调用A(double d)构造函数
	a1.func(2.0);
}

输出结果:

加了explicit关键字后,可防止以上隐式类类型转换发生

class A {
public:
	A() = default;
	explicit A(double d) {
		//其他代码同上
	}
	explicit A(int x, double d=2.5) {
		//其他代码同上
	}
	explicit A(const A&a) {
		//其他代码同上
	}
	
};
int main(void)
{
	
	//通过直接初始化调用explicit构造函数,而不能使用拷贝初始化
	A a1(1.5);
	A a2(1);
	A a3(a1);
	//尽管编译器不会将explicit的构造函数用于隐式转换过程,但是我们可以使用以下方式进行显示转换
	a1.func(A(2.0));
}

发生隐式转换的一种情况是当我们执行拷贝形式的初始化时(使用=)。此时,我们只能使用直接初始化而不能使用explicit构造函数

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/836672.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号