本文整理一些C++11的新特性,歡迎補充。
**auto關鍵字**?
在C++11之前,auto關鍵字用來指定存儲期。在新標準中,它的功能變為類型推斷。auto現在成了一個類型的占位符,通知編譯器去根據初始化代碼推斷所聲明變量的真實類型。各種作用域內聲明變量都可以用到它。例如,名空間中,程序塊中,或是for循環的初始化語句中。
~~~
auto i = 42; // i is an int
auto l = 42LL; // l is an long long
auto p = new foo(); // p is a foo*
~~~
使用auto通常意味著更短的代碼(除非你所用類型是int,它會比auto少一個字母)。試想一下當你遍歷STL容器時需要聲明的那些迭代器(iterator)。現在不需要去聲明那些typedef就可以得到簡潔的代碼了。
~~~
std::map<std::string, std::vector<int>> map;
for(auto it = begin(map); it != end(map); ++it)
{
}
~~~
需要注意的是,auto不能用來聲明函數的返回值。但**如果函數有一個尾隨的返回類型時,auto是可以出現在函數聲明中返回值位置**。這種情況下,auto并不是告訴編譯器去推斷返回類型,而是指引編譯器去函數的末端尋找返回值類型。在下面這個例子中,函數的返回值類型就是operator+操作符作用在T1、T2類型變量上的返回值類型。
~~~
template <typename T1, typename T2>
auto compose(T1 t1, T2 t2) -> **decltype**(t1 + t2)
{
return t1+t2;
}
auto v = compose(2, 3.14); // v's type is double
~~~
**nullptr**?
以前都是用0來表示空指針的,但由于0可以被隱式類型轉換為整形,這就會存在一些問題。關鍵字nullptr是std::nullptr_t類型的值,用來指代空指針。nullptr和任何指針類型以及類成員指針類型的空值之間可以發生隱式類型轉換,同樣也可以隱式轉換為bool型(取值為false)。但是不存在到整形的隱式類型轉換。
~~~
void foo(int* p) {}
void bar(std::shared_ptr<int> p) {}
int* p1 = NULL;
int* p2 = nullptr;
if(p1 == p2)
{
}
foo(nullptr);
bar(nullptr);
bool f = nullptr;
int i = nullptr; // error: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type
~~~
為了向前兼容,0仍然是個合法的空指針值。
**基于范圍的for循環**?
為了在遍歷容器時支持”foreach”用法,C++11擴展了for語句的語法。用這個新的寫法,可以遍歷C類型的數組、初始化列表以及任何重載了非成員的begin()和end()函數的類型。?
如果你只是想對集合或數組的每個元素做一些操作,而不關心下標、迭代器位置或者元素個數,那么這種foreach的for循環將會非常有用。
~~~
std::map<std::string, std::vector<int>> map;
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
map["one"] = v;
for(const auto& kvp : map)
{
std::cout << kvp.first << std::endl;
for(auto v : kvp.second)
{
std::cout << v << std::endl;
}
}
int arr[] = {1,2,3,4,5};
for(int& e : arr)
{
e = e*e;
}
~~~
**Override和final**?
看下面這個例子:
~~~
class B
{
public:
virtual void f(short) {std::cout << "B::f" << std::endl;}
};
class D : public B
{
public:
virtual void f(int) {std::cout << "D::f" << std::endl;}
};
~~~
D::f 按理應當重寫 B::f。然而二者的聲明是不同的,一個參數是short,另一個是int。因此D::f只是擁有同樣名字的另一個函數(重載)而不是重寫。當你通過B類型的指針調用f()可能會期望打印出D::f,但實際上則會打出 B::f 。?
另一個很微妙的錯誤情況:參數相同,但是基類的函數是const的,派生類的函數卻不是。
~~~
class B
{
public:
virtual void f(int) const {std::cout << "B::f " << std::endl;}
};
class D : public B
{
public:
virtual void f(int) {std::cout << "D::f" << std::endl;}
};
~~~
同樣,這兩個函數是重載而不是重寫,所以你通過B類型指針調用f()將打印B::f,而不是D::f。?
幸運的是,現在有一種方式能描述你的意圖。新標準加入了兩個新的標識符:?
override,表示函數應當重寫基類中的虛函數。?
final,表示派生類不應當重寫這個虛函數。?
第一個的例子如下:
~~~
class B
{
public:
virtual void f(short) {std::cout << "B::f" << std::endl;}
};
class D : public B
{
public:
virtual void f(int) override {std::cout << "D::f" << std::endl;}
};
~~~
現在這將觸發一個編譯錯誤:?
‘D::f’ : method with override specifier ‘override’ did not override any base class methods?
另一方面,如果你希望函數不要再被派生類進一步重寫,你可以把它標識為final。可以在基類或任何派生類中使用final。在派生類中,可以同時使用override和final標識。
~~~
class B
{
public:
virtual void f(int) {std::cout << "B::f" << std::endl;}
};
class D : public B
{
public:
virtual void f(int) override final {std::cout << "D::f" << std::endl;}
};
class F : public D
{
public:
virtual void f(int) override {std::cout << "F::f" << std::endl;}
};
~~~
被標記成final的函數將不能再被F::f重寫。
**強類型枚舉**?
傳統的C++枚舉類型存在一些缺陷:它們會將枚舉常量暴露在外層作用域中(這可能導致名字沖突,如果同一個作用域中存在兩個不同的枚舉類型,但是具有相同的枚舉常量就會沖突),而且它們會被隱式轉換為整形,無法擁有特定的用戶定義類型。?
在C++11中通過引入了一個稱為**強類型枚舉的新類型**,修正了這種情況。強類型枚舉由關鍵字**enum class**標識。它不會將枚舉常量暴露到外層作用域中,也不會隱式轉換為整形,并且擁有用戶指定的特定類型(傳統枚舉也增加了這個性質)。
~~~
enum class Options {None, One, All};
Options o = Options::All;
~~~
**智能指針**?
詳見博客《[淺析C++中的智能指針](http://blog.csdn.net/wangshubo1989/article/details/48337955 "C++中的智能指針")》
- 前言
- 吐血整理C++11新特性
- C++11新特性之std::function
- c++11特性之正則表達式
- c++11特性之Lambda表達式
- c++11特性之override和final關鍵字
- c++11特性之std::thread--初識
- c++11特性之std::thread--初識二
- c++11特性之initializer_list
- c++11特性之std::thread--進階
- c++11特性之std::thread--進階二
- C++11新特性之 CALLBACKS
- C++11新特性之 std::array container
- C++11新特性之 nullptr
- C++11新特性之 rvalue Reference(右值引用)
- C++11新特性之 Move semantics(移動語義)
- C++11新特性之 default and delete specifiers
- C++11新特性之 Static assertions 和constructor delegation
- 開始使用C++11的幾個理由
- C++11新特性之 std::future and std::async