C++11的標准已經確定,除了增加了不少庫函數外,在語法方便也得到了許多增強。其中如下幾個語法就是我比較喜歡的:
自動類型推導auto
現在c++終於在編譯器級別支持類似C#的var關鍵字了,在c++裡的關鍵字是auto,基本用法如下:
auto i = 0; //int
auto c = 'c'; //char
auto s = "hello world"; //const char*
auto關鍵字的一個很直觀的好處是我們可以簡化stl容器遍歷裡的那個iterator了:
for(auto it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
Lambda 表達式
Lambda 表達式的主要用來構造匿名函數,它可以替換絕大部分場景的仿函數(感覺把剛剛引入STL庫的std::bind也順手給秒了),並且有更好的可讀性。一個簡單的示例如下:
auto k = [](int x, int y)
{ return x + y; };
cout << k(3, 2) << endl;
可以看到,它的基本語法形式為: [capture] (parameters) {body},後兩部分和C#的匿名函數的語法非常,但最前面的 [capture] 的作用是什麼呢?它是用來引用表達式外的局部變量的,例如:
int i1 = 0, i2 = 3;
auto k = [&i1, &i2] () { i1 = 3; i2 = 5; };
cout << i1 << " " << i2 << endl;
除了是前面所述的普通局部變量外,還可以是如下特殊符號:
Range-based for-loop
這個其實就是類似C#裡面的foreach,不過它並沒有引入新關鍵字,而是直接用的for
int p[8] = {2, 3, 5, 7, 11, 13, 17, 19};
for (auto& i: p)
{
printf("%d ", i);
}
除了支持數組外,它也支持stl中的迭代器遍歷,for_each函數基本上可以下崗了。至於它的原理,可以參考這篇文章。
枚舉類
在C語言中,枚舉等同於一個數字常量,編譯器並沒有對它做過多的處理,在C++11中,引入了enum class以替換枚舉,它的定義方式如下:
enum class Color { Red, Blue};
enum class Fruit { Banana, Apple};
除了多加了一個class外,沒有別的變化,但它定義的枚舉功能和C#中的枚舉相似。和C語言的傳統枚舉相比,主要有如下兩個區別:
強類型的語法檢查可以有效防止枚舉之間的非法轉換和比較,Color::Red == Fruit::Banana之類的判斷無法編譯通過。
而枚舉名稱只需要在class范圍內唯一則有效縮短了枚舉的長度,對於Color枚舉,在C語言中,為了防止歧義和命名沖突,往往需要定義為Color_Red、Color_Blue的形式。
靜態斷言static_assert
靜態斷言主要提供了在代碼中實現編譯期可以確定的斷言,如果出錯則直接以編譯錯誤的形式顯示出來,從而加強程序的健壯性。這個其實就是以前的boost.static_assert,不過在編譯器的支持下變得更加友好了。示例如下:
static_assert(sizeof(int) == 4, "int needs to be 4 bytes to use this code");
密閉類和密閉方法
C++11中也引入了類似C# seal關鍵字的方式實現密閉類和密閉方法,以阻止對象繼承、方法重載。不過它的關鍵字是final,和java類似。
final類
class Base final
{
};
class Derived : public Base //繼承密閉類,語法錯誤
{
};
final方法
class Base
{
virtual void A() final;
};
class Derived : public Base
{
virtual void A(); //重寫密閉方法,編譯出錯
};
顯式覆蓋
對於虛函數的重寫,在c++ 11中可以通過關鍵字顯式覆蓋,從而獲得更嚴格的語法檢查。
class Base
{
virtual void A(float=0.0);
virtual void B() const;
virtual void C();
void D();
};
class Derived: public Base
{
virtual void A(int=0) override; //定義不一致,編譯錯誤
virtual void B() override; //返回類型不是const,編譯錯誤
virtual void C() override; //正確
void D() override; //不是虛函數,編譯錯誤
};
PS:我倒覺得這個語法檢查應該默認就加上,通過關鍵字顯式去掉檢查,而不是像這樣顯式打開檢查。萬惡的向上兼容呀。
其它
其它還有幾個語法我也很喜歡,如取消字符串轉義、委托構造函數、deleted和defaulted成員函數、統一的初始化語法等,但這些在VC裡面還不支持,無法實現跨平台開發,暫時就不介紹了。