C++11第一部分:C++11的简单介绍
前言
相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140
个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率。
一、列表初始化
(1)C++98中的初始化问题
在C++98中,标准允许使用{}对数组元素进行初始化,如
int array1[] = {1,2,3,4,5};
int array2[5] = {0};
对于自定义类型,却无法使用这样的初始化,如
vector<int> v{1,2,3,4,5};
就无法通过编译,导致每次定义vector时,都需要先把vector定义出来,然后使用循环对其赋初始值,非常不方便。
C++11解决:C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
(2)内置类型的列表初始化
int main()
{
//内置类型变量
int x1 = {10};
int x2{10};
int x3 = 1+2;
int x4 = {1+2};
int x5{1+2};
//数组
int arr1[5] {1,2,3,4,5};
int arr2[]{1,2,3,4,5};
//动态数组,在C++98中不支持
int* arr3 = new int[5]{1,2,3,4,5};
//标准容器
vector<int> v{1,2,3,4,5};
map<int, int> m{{1,1}, {2,2,},{3,3},{4,4}};
return 0;
}
可以在{}前使用=,和不使用没什么区别。
(3)自定义类型的列表初始化
支持对单个对象的列表初始化
class Point
{
public:
Point(int x = 0, int y = 0): _x(x), _y(y)
{}
private:
int _x;
int _y;
};
int main()
{
Pointer p{ 1, 2 };
return 0;
}
多个对象的列表初始化
多个对象想要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数即可。注意:initializer_list是系统自定义的类模板,该类模板中主要有三个方法:begin()、end()迭代器以及获取区间中元素个数的方法size()。,就是说initializer_list让容器初始化变简单,构造函数和拷贝构造函数使用其他函数当初始化列表。
#include <initializer_list>
template<class T>
class Vector {
public:
// ...
Vector(initializer_list<T> l): _capacity(l.size()), _size(0)
{
_array = new T[_capacity];
for(auto e : l)
_array[_size++] = e;
}
Vector<T>& operator=(initializer_list<T> l) {
delete[] _array;
size_t i = 0;
for (auto e : l)
_array[i++] = e;
return *this;
}
// ...
private:
T* _array;
size_t _capacity;
size_t _size;
}
二、变量类型推导
1.类型推导为什么需要
在定义变量时,必须先给出变量的实际类型,编译器才允许定义,但有些情况下可能不知道需要实际类型怎么给,或者类型写起来特别复杂。
类型可能给错,可能出现编译问题,还有迭代器的类型实在是太复杂。
解决:C++11中,可以使用auto来根据变量初始化表达式类型推导变量的实际类型,可以给程序的书写提供许多方便。将程序中c与it的类型换成auto,程序可以通过编译,而且更加简洁。
下面是C++11新的类型推导关键字
2. decltype类型推导
对于auto:auto使用的前提是:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型。但有时候可能需要根据表达式运行完成之后结果的类型进行推导,因为编译期间,代码不会运行,此时auto也就无能为力.
比如
template<class T1, class T2>
T1 Add(const T1& left, const T2& right)
{
return left + right;
}
如果能用加完之后结果的实际类型作为函数的返回值类型就不会出错,但这需要程序运行完才能知道结果的实际类型。
C++98中支持:
type_id只能查看类型不能用其结果类定义类型
dynamic_cast只能应用于含有虚函数的继承体系中
运行时类型识别的缺陷是降低程序运行的效率。..所以我们需要解决这个问题,
decltype:decltype是根据表达式的实际类型推演出定义变量时所用的类型。
1.推演表达式类型作为变量的定义类型
int main()
{
int a = 10;
int b = 20;
//用decltype推演a+b的实际类型,作为定义c的类型
decltype(a+b) c;
cout<<typeid(c).name()<<endl;
return 0;
}
2.推演函数返回值的类型
void* GetMemory(size_t size)
{
return malloc(size);
}
int main()
{
//如果没有带参数,推导函数的类型
cout << typeid(decltype(GetMemory)).name() << endl;
//如果带参数列表,推导的是函数返回值的类型,注意:此处只是推演,不会执行函数
cout << typeid(decltype(GetMemory(0))).name() <<endl;
return 0;
}
decltype只会进行推演,不会执行函数,这样就不会占用空间。
总结
对列表初始化的认识,使用initializer_list进行初始化列表,方便不在进行循环初始化容器,让容器和内置类型一样可以直接初始化,
对变量类型推导,是解决类型太长,太难写的情况下使用,而auto在一定的场景下不能使用,比如对函数返回类型,要进行运行函数才能推导,会增加消耗,而decltpye不需要执行函数就可以对函数的返回值值进行推导。
更多推荐

所有评论(0)