1. C++11簡(jiǎn)介
在2003年C++標(biāo)準(zhǔn)委員會(huì)曾經(jīng)提交了一份技術(shù)勘誤表(簡(jiǎn)稱TC1),使得C++03這個(gè)名字取代了C++98稱為C++11之前的最新C++標(biāo)準(zhǔn)名稱。
不過(guò)由于C++03(TC1)主要是對(duì)C++98標(biāo)準(zhǔn)中的漏洞進(jìn)行修復(fù),語(yǔ)言的核心部分則沒有改動(dòng),因此人們習(xí)慣性的把兩個(gè)標(biāo)準(zhǔn)合并稱為C++98/03標(biāo)準(zhǔn)。
從C++0x到C++11,C++標(biāo)準(zhǔn)10年磨一劍,第二個(gè)真正意義上的標(biāo)準(zhǔn)珊珊來(lái)遲
相比于C++98/03,C++11則帶來(lái)了數(shù)量可觀的變化,其中包含了約140個(gè)新特性,以及對(duì)C++03標(biāo)準(zhǔn)中約600個(gè)缺陷的修正,這使得C++11更像是從C++98/03中孕育出的一種新語(yǔ)言。
相比較而言,C++11能更好地用于系統(tǒng)開發(fā)和庫(kù)開發(fā)、語(yǔ)法更加泛化和簡(jiǎn)單化、更加穩(wěn)定和安全,不僅功能更強(qiáng)大,而且能提升程序員的開發(fā)效率,公司實(shí)際項(xiàng)目開發(fā)中也用得比較多,所以我們要作為一個(gè)重點(diǎn)去學(xué)習(xí)。
C++11增加的語(yǔ)法特性非常篇幅非常多,我們這里沒辦法一 一講解,所以最近的幾篇文章主要講解實(shí)際中比較實(shí)用的語(yǔ)法
官方文檔
小故事:
1998年是C++標(biāo)準(zhǔn)委員會(huì)成立的第一年,本來(lái)計(jì)劃以后每5年視實(shí)際需要更新一次標(biāo)準(zhǔn),C++國(guó)際標(biāo)準(zhǔn)委員會(huì)在研究C++ 03的下一個(gè)版本的時(shí)候,一開始計(jì)劃是2007年發(fā)布,所以最初這個(gè)標(biāo)準(zhǔn)叫C++ 07。但是到06年的時(shí)候,官方覺得2007年肯定完不成C++ 07,而且官方覺得2008年可能也完不成。最后干脆叫C++ 0x。x的意思是不知道到底能在07還是08還是09年完成。
結(jié)果2010年的時(shí)候也沒完成,最后在2011年終于完成了C++標(biāo)準(zhǔn)。所以最終定名為C++11。
2. 統(tǒng)一的列表初始化
首先聲明一下:
這個(gè)列表初始化和我們類和對(duì)象那里學(xué)的初始化列表不是一個(gè)概念,是不同的。
2.1 {}初始化
在C++98中,標(biāo)準(zhǔn)允許使用花括號(hào){}對(duì)數(shù)組或者結(jié)構(gòu)體元素進(jìn)行統(tǒng)一的列表初始值設(shè)定。
比如:
那我們C語(yǔ)言里面其實(shí)就是這樣搞的嘛,所以可以認(rèn)為C++支持這樣就是因?yàn)橐嫒軨嘛
那么在C++11中:
C++11擴(kuò)大了用大括號(hào)括起的列表的使用范圍,使其可用于所有的內(nèi)置類型和用戶自定義的類型,使用初始化列表時(shí),可添加等號(hào)(=),也可不添加。
??,我們來(lái)演示一下:
大家看,C++11支持我們這樣使用{}初始化,并且賦值=
也可以省略
然后要注意:
這樣寫是咋回事?
??,這是不是可以認(rèn)為是調(diào)int的默認(rèn)構(gòu)造啊,我們之前說(shuō)過(guò),有了模板之后,內(nèi)置類型也需要有構(gòu)造函數(shù)了。
然后:
C++11中列表初始化也可以適用于new表達(dá)式中
另外:
創(chuàng)建對(duì)象時(shí)也可以使用列表初始化方式調(diào)用構(gòu)造函數(shù)初始化
比如我們之前寫過(guò)的日期類:
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date(int year, int month, int day)" << endl;
}
private:
int _year;
int _month;
int _day;
};
2.2 std::initializer_list
那除了上面的場(chǎng)景呢,C++11還支持了STL里面的容器也可以這樣去初始化
比如:
??,都是可以的,其它容器也可以,大家可以自己試。
那大家思考一下,在容器這里它是如何支持可以這樣寫的呢?
首先我們來(lái)看一下這個(gè):
這里我們直接給一個(gè)大括號(hào),里面放一些元素,這是個(gè)啥啊。
之前我們初始化數(shù)組可以這樣寫嘛,那它在這里也是一個(gè)數(shù)組嗎?
那數(shù)組怎么直接賦值給一個(gè)vector呢?
??,那不清楚的話我們可以打印看一下它的類型是什么:
大家看,它的類型是一個(gè)叫做initializer_list<int>
的東西。
那為什么這個(gè)東西可以賦值給vector呢?
??,大家看紅色圈出來(lái)的部分,C++11給STL中的這些容器增加了這樣一個(gè)構(gòu)造函數(shù)。
支持用initializer_list類型的對(duì)象去構(gòu)造vector這些容器。
所以正常使用這個(gè)構(gòu)造應(yīng)該是這樣寫:
那我們寫成這樣
當(dāng)然也可以,因?yàn)闃?gòu)造函數(shù)支持隱式類型轉(zhuǎn)換嘛。
那initializer_list這個(gè)類是個(gè)啥呢?
initializer_list是C++11引入的一種特殊類型,用于簡(jiǎn)化初始化列表的使用。它可以在構(gòu)造函數(shù)或函數(shù)參數(shù)中以列表的形式傳遞一組值。
可以認(rèn)為它就是一個(gè)常量數(shù)組,存儲(chǔ)在常量區(qū),initializer_list對(duì)象中的元素永遠(yuǎn)是常量值,我們無(wú)法改變initializer_list對(duì)象中元素的值。
這是它的一些接口
那我們接下來(lái)做一件事情:
我們之前不是模擬實(shí)現(xiàn)過(guò)STL里面的各種容器的,那以vector為例,我們來(lái)對(duì)它改造一下,讓它也支持用initializer_list進(jìn)行{}初始化和賦值。
怎么做呢?給它增加這個(gè)構(gòu)造函數(shù)就行了
??,每增加之前我們自己的vector肯定是不行的,而且大家看這個(gè)報(bào)錯(cuò),編譯器自動(dòng)就把后面的常量數(shù)組識(shí)別成initializer list類型了
我們來(lái)寫一下:
這下我們?cè)賮?lái)運(yùn)行
就可以了
然后再提一下就是
如果這里用迭代器遍歷的話前面加一個(gè)typename,這個(gè)我們之前也提過(guò),就是類模板里面直接取內(nèi)嵌類型它會(huì)分不清是類型還是靜態(tài)成員變量。
當(dāng)然不止vector可以,我們說(shuō)了C++11給STL這幾個(gè)容器都增加了initializer_list版本的構(gòu)造:
當(dāng)然除了構(gòu)造還支持了initializer_list版本的賦值重載:
3. 聲明
c++11提供了多種簡(jiǎn)化聲明的方式
3.1 auto
那auto呢我們?cè)贑++專欄第一篇文章C++入門的時(shí)候就介紹過(guò)了,所以這里就不再重復(fù)了
3.2 decltype
再來(lái)學(xué)一個(gè)C++11引入的關(guān)鍵字——decltype
什么作用呢?
decltype是可以獲取表達(dá)式或變量類型的關(guān)鍵字
我們之前用過(guò)typeid(變量/表達(dá)式).name()
可以獲取變量或表達(dá)式的類型,然后我們可以打印出來(lái)查看,而使用decltype我們可以獲取類型并使用這個(gè)類型
比如:
但是大家可能會(huì)說(shuō):
上面的場(chǎng)景用auto也是可以的啊。
確實(shí),但是有的場(chǎng)景auto就不行,比如:
我們要定義一個(gè)vector,要求vector里面存儲(chǔ)的數(shù)據(jù)類型跟表達(dá)式x*y的返回類型一致
大家看,這個(gè)場(chǎng)景auto就不行了吧
4. nullptr
這個(gè)我們之前也介紹過(guò)了
5. 范圍for循環(huán)
也介紹過(guò)了
6. 智能指針
關(guān)于智能指針我們后面會(huì)單獨(dú)作為一個(gè)章節(jié)來(lái)給大家講解
7. C++11STL中的一些變化
下面我們來(lái)分析一下C++11中STL與之前相比有了那些變化
首先它增加了一些新容器:
用橘色圈起來(lái)是C++11中的一些幾個(gè)新容器,我們也都介紹過(guò)了,但是實(shí)際最有用的是unordered_map和unordered_set,另外兩個(gè)就顯得非常雞肋
其次呢就是增加了一些新方法:
比如提供了cbegin和cend方法返回const迭代器等等,但是實(shí)際意義不大,因?yàn)閎egin和end也是可以返回const迭代器的,這些都是屬于錦上添花的操作。
實(shí)際上C++11更新后,容器中增加的新方法最實(shí)用的就是插入接口函數(shù)的右值引用版本
那關(guān)于這里3、4兩點(diǎn)提到的右值引用和移動(dòng)語(yǔ)義我們后面也會(huì)花大量篇幅給大家講解…
8. 演示代碼
把上面演示過(guò)的代碼給大家:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-731706.html
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//struct Point
//{
// int _x;
// int _y;
//};
//
//int main()
//{
// int a(4);
//
// int b = { 2 };
// int c{ 3 };
//
// int arr[]{ 1,2,3,4,5 };
//
// Point p{ 1,2 };
//
// // C++11中列表初始化也可以適用于new表達(dá)式中
// int* pa = new int{ 5 };
// cout << *pa << endl;
// return 0;
//}
//class Date
//{
//public:
// Date(int year, int month, int day)
// :_year(year)
// , _month(month)
// , _day(day)
// {
// cout << "Date(int year, int month, int day)" << endl;
// }
//private:
// int _year;
// int _month;
// int _day;
//};
//int main()
//{
// Date d1(2022, 1, 1); // old style
//
// // C++11支持的列表初始化,這里會(huì)調(diào)用構(gòu)造函數(shù)初始化
// Date d2 = { 2022, 1, 2 };
// Date d3{ 2022, 1, 3 };
// return 0;
//}
#include <vector>
#include <list>
//int main()
//{
// vector<int> v = { 1,2,3,4 };
//
// vector<int> v2({ 1,2,3,4 });
//
// list<int> lt = { 2,4,6,8,9 };
//
// initializer_list<int> il = { 1,2,3,4,5,6,7,8 };
//
// vector<int> v3 = il;
//
// return 0;
//}
int main()
{
const int x = 1;
double y = 2.2;
//decltype(x * y) ret; // ret的類型是double
//decltype(&x) p; // p的類型是const int*
auto ret = x * y;
auto p = &x;
vector<decltype(x* y)> v;
cout << typeid(ret).name() << endl;
cout << typeid(p).name() << endl;
return 0;
}
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-731706.html
到了這里,關(guān)于【C++11】{}初始化、std::initializer_list、decltype、STL新增容器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!