C++学习记录——이십유 C++11(2)


1、类的新功能

1、移动构造和移动赋值

在这里插入图片描述

逐成员按字节拷贝就是浅拷贝。一个类中,如果达成默认移动构造的要求,那么传右值就会使用移动构造了,传左值还是拷贝构造。

2、default、delete

强制生成默认函数。比如自己写了拷贝构造,那么移动构造就不会默认生成,那么就可以用default来强制生成。

Person (Person&& p) = default;//移动构造
Person& operator=(Person&& p) = default;//移动赋值
//原本括号里都是const Person& p

但有些编译器会有别的问题,比如用默认的拷贝构造和赋值,再强制生成默认的移动可能就无法生成,要不都用强制生成,要不自己写拷贝构造和赋值。

delete则是禁止生成默认函数。也是= delete写法。

之前学过的final和override,final会让类不能被继承,成员函数不能被重写;override检查派生类的虚函数是否完成重写。

2、可变参数模板

template <class ...Args>
void show(Args... args)
{
	;
}

三个点就代表可变参数,Args是一个模板参数包,args是一个函数形参参数包,声明一个参数包Args… args,这个参数包中可以包含0到任意个模板参数。传的时候可以传各种类型的参数。比如传一个字符和一个整数,C++11中这里的可变参数也就是类型不同的参数了。

但在函数中的写法也会有所变化

template <class ...Args>
void show(Args... args)
{
	cout << sizeof...(args) << endl;//对于三个点,编译器会自己判断,生成多少个模板参数
}

int main()
{
	show();
	show('x');
	show('x', 'y');
	show('x', 1);
	return 0l;
}

在这里插入图片描述

如何解析可变参数包?typeid不支持使用,不能这样写typeid…(args).name()。

void show()
{
	cout << endl;
}

template <class T, class ...Args>
void show(const T& val, Args... args)
{
	//cout << sizeof...(args) << endl;
	cout << val << " ";
	show(args...);
}

int main()
{
	show();
	show('x');
	show('x', 'y');
	show('x', 1); 
	show('x', 1, string("abcd"));
	return 0l;
}

这里用的递归思维,第一个show调用没有参数的show,所以直接打印空;第二个就是调用带参数的show,字符x传给val,而参数包此时就是0个参数。第三个开始就是多个参数传过去,val是字符x,参数包是字符y,第一次打印完val,然后再次调用show,此时传过去args…,那么val就是y,参数包是0个参数。

可以看调用了多少次。

void show()
{
	cout << endl;
}

template <class T, class ...Args>
void show(const T& val, Args... args)
{
	//cout << sizeof...(args) << endl;
	cout << __FUNCTION__ << "(" << sizeof...(args) << ")" << endl;
	cout << val << " ";
	show(args...);
}

int main()
{
	//show();
	//show('x');
	//show('x', 'y');
	//show('x', 1); 
	show('x', 1, string("abcd"));
	return 0l;
}

在这里插入图片描述

C++的线程会用到这个可变参数包。

还有这样的写法

template<class T>
void PrintArg(T t)
{
	cout << t << " ";
}

template<class ...Args>
void show(Args... args)
{
	int arr[] = { (PrintArg(args), 0)... };
	cout << endl;
}

int main()
{
	show(1, 'A', string("abcd"));
	return 0;
}

在这里插入图片描述
后面的三个点是必须要写的形式,用了逗号表达式,逗号表达式取右边的,因为要初始化这int数组,所以这个0,变成什么数字都可以,如果不加这个逗号表达式,直接写int arr[] = {PrintArg(args)… } 然后在PrintArg函数里写上return 0即可。把三个点放在括号外面可以一个个传过去,具体传多少,编译器知道有多少个模板参数;如果是放在括号里args…,那就是全部传了过去,那就不对了。

在编译器里就变成这样。

void show(char a1, char a2, sting a3)
{
    int arr[] = {PrintArg(a1), PrintArg(a2), PrintArg(a3)};
	cout << endl;
}

可变参数包让编译器的负担加重了。

实际写的时候更倾向于Args&&… args,在模板这样的引用就是万能引用,也就是引用折叠,因为传自定义类型的时候,像string,就会是传值引用

3、STL容器的emplace

库中的类的插入部分添加了emplace_back这样的函数,它就用了可变参数包,在普通插入方面push_back其实没有太多区别,用法也都一样,但在传入临时变量会有一定区别,比如在list中emplace_back(“asdasda”),这时候push_back就是先构造匿名对象再传参到右值版本,然后移动构造转移资源;而emplace_back则是直接构造,它会推导成char*类型,然后往下传给要添加的节点,最后构造。

深拷贝的类差别不大,移动构造有一定差距,浅拷贝时,像日期类,传左值就比右值消耗大。emplace不能接收初始化的列表,比如{2023, 8, 26},但是可以emplace_back(Date(2023, 8, 26))和emplace_back(2023, 8, 26)是可以的,这两个就是构造+移动构造和直接构造。

本篇gitee

结束。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值