C++_进阶:C++11新增语法(2)

1.新的类功能

1.1 新的默认成员函数

在这里插入图片描述

C++入门 类和对象:构造函数,析构函数,拷贝构造 中,提及类的默认成员函数有以上6个,C++11 新增了两个:移动构造函数移动赋值运算符重载,所以之后的类的默认成员函数有8个了 。

针对移动构造函数和移动赋值运算符重载有一点需要注意:

  1. 如果你没有自己实现 移动构造函数 / 移动赋值重载函数,并且没有实现析构函数拷贝构造拷贝赋值重载,那么编译器会自动生成一个默认移动构造函数 / 默认移动赋值重载函数
    在这里插入图片描述
  2. 默认生成的移动构造函数 / 移动赋值重载函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造/移动赋值,如果实现了就调用移动构造/移动赋值,没有实现就调用拷贝构造/移动赋值。
    在这里插入图片描述

2. 类成员变量初始化

C++11允许在类定义时给成员变量初始缺省值,默认生成构造函数会使用这些缺省值初始化

3. 强制生成默认函数的关键字default

C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用default关键字显示指定移动构造生成。

class Person
{
   
public:
	//显示生成拷贝构造
	Person(const Person& tmp)
	{
   
		age = tmp.age;
		name = tmp.name;
	}
	//强制生成移动拷贝
	Person(Person&& tmp) = default;

	string name;
	int age;
};

4. 禁止生成默认函数的关键字delete:

如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明不实现,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

//C++98的方法,把对应函数声明在private中,
//并且只声明不实现
class Date
{
   
public:
	//...实现的其他函数
private:
	Date(const Date& tmp);
	int year;
	int month;
	int day;
};
//C++11的方法,直接delete
class Date
{
   
public:
	Date(const Date& tmp) = delete;
private:
	int year;
	int month;
	int day;
};

5. final与override关键字

C++_进阶:多态详解中有介绍。

2. 可变参数模板

相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板

可变参数模板的语法

// Args 是一个模板参数包类型,写在<>中,前面要+...
// args是一个函数形参参数包,写在形参中,声明时Args后要+...
template <class ...Args>
void ShowList(Args... args)
{
   }


int main()
{
   
	ShowList(3 , 3.3 , 3 ,3.3);
}

在这里插入图片描述
上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。我们无法直接获取参数包args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数。

1️⃣递归函数方式展开参数包

// 递归终止函数
template <class T>
void ShowList(const T& t)
{
   
	cout << t << endl;
}
// 展开函数
template <class T, class ...Args>
void ShowList(T value, Args... args)
{
   
	cout << value << " ";
	ShowList(args...);
}
int main()
{
   
	ShowList(1, 'A', std::string("sort"));
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
输出结果:
在这里插入图片描述


2️⃣逗号表达式展开参数包

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

//展开函数
template <class ...Args>
void ShowList(Args... args)
{
   
	int arr[] = {
    (PrintArg(args), 0)... };
	cout << endl;
}

int main()
{
   
	ShowList(1, 'A', std::string("sort"));
	return 0;
}

这种展开参数包的方式,不需要通过递归终止函数,是直接在expand函数体中展开的, printarg不是一个递归终止函数,只是一个处理参数包中每一个参数的函数。这种就地展开参数包的方式实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。

expand函数中的逗号表达式:(printarg(args), 0),也是按照这个执行顺序,先执行
printarg(args),再得到逗号表达式的结果0。同时还用到了C++11的另外一个特性——初始化列表,通过初始化列表来初始化一个变长数组
在这里插入图片描述

在这里插入图片描述

在STL容器中,empalce相关接口函数就是用可变参数模板实现的。
在这里插入图片描述
在这里插入图片描述

// emplace_back的接口
template <class... Args>
void emplace_back (Args&&... args);
//

Args&&… 万能引用参数包类型,能接受一个及以上的左值或者右值

emplace的功能是尾插&#x

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值