數據類型 (Data type)
int, long int, double, struct, char *, float [], int (*f)()…
計算機程序構造塊
計算機程序構造塊是不同大小粒度的計算機程序組成部分,它包括變量、表達式、函數或者模塊等。
類型系統 (Type System)
類型系統:在編程語言中,“類型系統”是將“type”屬性指定給不同計算機程序構造塊的規則集
為什么使用類型系統:減少程序中可能出現的bug
1、定義不同程序塊之間的接口
2、檢查多個塊之間是否以一致的方式連接在一起
類型系統分為:靜態類型和動態類型
類型系統存在于我們編寫程序中,編譯器會幫我們檢查類型系統。
如果檢查發生在編譯期(編譯的時候檢查類型系統是否一致),稱為靜態類型
如果檢查發生在運行期(執行的時候檢查類型系統是否一致),稱為動態類型
如果檢查同時存在與編譯期間和運行期間,稱為混合類型
C、C++、Java是靜態類型
Python是動態類型
Automatic Type Deduction: auto (C++11) 自動類型推導:auto關鍵字
C++03及之前的標準種,auto放在變量聲明之前,聲明變量的存儲策略。但是這個關鍵字常省略不寫。
C++11中,auto關鍵字放在變量之前,作用是在聲明變量的時候根據變量初始值的類型自動為此變量選擇匹配的類型
例:
int a = 10;
auto au_a = a;//自動類型推斷,au_a為int類型
cout << typeid(au_a).name() << endl;
result:
int
注意點:
1、auto 變量必須在定義時初始化,這類似于const關鍵字
auto a1 = 10; //正確
auto b1; //錯誤,編譯器無法推導b1的類型
b1 = 10;
2、定義在一個auto序列的變量必須始終推導成同一類型
auto a4 = 10, a5{20}; //正確
auto b4{10}, b5 = 20.0; //錯誤,沒有推導為同一類型
3、如果初始化表達式是引用或const,則去除引用或const語義。
int a{10}; int &b = a;
auto c = b; //c的類型為int而非int&(去除引用)
const int a1{10};
auto b1 = a1; //b1的類型為int而非const int(去除const)
4、如果auto關鍵字帶上&號,則不去除引用或const語意
int a = 10; int& b = a;
auto& d = b;//此時d的類型才為int&
const int a2 = 10;
auto& b2 = a2;//因為auto帶上&,故不去除const,b2類型為const in
5、初始化表達式為數組時,auto關鍵字推導類型為指針
int a3[3] = { 1, 2, 3 };
auto b3 = a3;
cout << typeid(b3).name() << endl; //輸出int * (輸出與編譯器有關)
6、若表達式為數組且auto帶上&,則推導類型為數組類型
int a7[3] = { 1, 2, 3 };
auto& b7 = a7;
cout << typeid(b7).name() << endl; //輸出int [3] (輸出與編譯器有關)
7、C++14中,auto可以作為函數的返回值類型和參數類型
auto max(int x , int y)
{return x>y?x:y;
}
我們在使用auto時有時會遇到一些特殊情況。
1、 “int x = 3;” 能變成auto形式嗎?
當我們非常希望能夠在變量定義的時候,【明確】地指出變量的類型,而且不希望隨便更改其類型,那么我們可以使用下面的方法:
auto x = int {3}; // 初始化列表auto y = int {3.0}; // 編譯器報錯,初始化列表不能窄化auto z = int (3.0); // C風格的強制類型轉換,z的值是整數3
2、 auto和初始化列表一起用 要避免在一行中使用直接列表初始化和拷貝列表初始化,也就是,下面的代碼是有問題的:
auto x { 1 }, y = { 2 }; // 不要同時使用直接和拷貝列表初始化
“AAA原則”:總是使用auto!
問題:能用auto聲明C風格的數組嗎?
如果你嘗試讓C++11編譯器編譯如下代碼,它會報錯
// 包含頭文件
// 聲明主函數
// ......
auto x[] = {1,2,3};
auto 不能用于聲明數組,否則無法通過編譯,報auto類型不能出現在頂級數組類型中。
也就是說auto只能是指針指向數組的而不能去聲明一個數組。
自動類型推導:decltype關鍵字
1、關鍵字decltype的用法
decltype利用已知類型聲明新變量。
有了auto,為什么還要整出一個decltype?原因是,我們有時候想要從表達式的類型推斷出要定義的變量類型,但不想用該表達式的值初始化變量。
decltype是在編譯期推導一個表達式的類型,而不用初始化,其語法格式有點像sizeof。它只做靜態分析,因此它不會導致已知類型表達式執行。
decltype 主要用于泛型編程(模板)
2、代碼示例
#include<iostream>
using namespace std;
int fun1() { return 10; }
auto fun2() { return 'g'; } // C++14
int main(){// Data type of x is same as return type of fun1()// and type of y is same as return type of fun2()decltype(fun1()) x; // 不會執行fun1()函數,相當于 int x;decltype(fun2()) y = fun2(); //auto y=>char y;cout << typeid(x).name() << endl;cout << typeid(y).name() << endl;return 0;
}
我們可以發現,我們將fun2的‘g’改變,例如改成4,y類型也改了。
這樣我們修改了返回值類型,程序仍然能夠正常運行。
這說明,使用類型推導是有好處的。
3、decltype與auto的對比
decltype和auto都是C++11自動類型推導的關鍵字。它們有很多差別:
auto忽略最上層的const,decltype則保留最上層的const
auto忽略原有類型的引用,decltype則保留原有類型的引用
對解引用操作,auto推斷出原有類型,decltype推斷出引用
4、auto推斷時會實際執行,decltype不會執行,只做分析。
總之在使用中過程中和const、引用和指針結合時需要特別小心。
小結
C++11對C++03的增強,或者說C++11的“Modern”的特點之一就是由auto和decltype構成的自動類型推導系統。
但是,auto與初始化列表結合,又有一些坑。你在寫代碼時如果經常將auto與列表初始化一起使用,那么會遇到一些問題。本節只介紹auto的常見用法。auto與初始化列表結合的坑,得由你自己去踩了。
為了說明auto有多么復雜,這里摘取 https://cppreference.com 網站列出的auto的語法格式: