文章目錄
- 1.auto關鍵字
-
- 1.1 auto關鍵字作用
- 1.2 auto關鍵字與頂層const和底層const
- 1.3 auto關鍵字與指針和引用
- 1.4 auto關鍵字與數組和函數
- 1.5 auto關鍵字與使用new動态配置設定
- 1.6 auto關鍵字與使用的場景
- 2.decltype關鍵字
-
- 2.1 decltype關鍵字作用
- 2.2 decltype關鍵字與頂層const和底層const
- 2.3 decltype關鍵字與普通變量
- 2.4 decltype關鍵字與指針和引用
- 2.5 decltype關鍵字總結
- 2.6 decltype關鍵字與decltype(auto)
- 2.7 decltype關鍵字與auto關鍵字差別
- 3.typeid關鍵字
-
- 3.1 typeid關鍵字作用
- 3.2 typeid關鍵字類型識别和函數
- 3.3 typeid關鍵字與類對象
- 4.initializer_list關鍵字
-
- 4.1 initializer_list關鍵字作用
- 4.2 initializer_list關鍵字與vector差別
- 4.3 initializer_list關鍵字提供的操作
- 5.explicit關鍵字
1.auto關鍵字
1.1 auto關鍵字作用
- 在C++11新标準中引進了auto類型說明符,使用它能夠讓編譯器代替我們去分析表達式所屬的類型。auto 自動類型推斷發生在編譯期,是以使用 auto 關鍵字不會降低程式的運作效率。
1.2 auto關鍵字與頂層const和底層const
- 如果定義的對象不是指針或者引用,則const屬性會被丢棄。例如:
int i=2;
const int ci=i,&cr=ci;
auto a=ci; //a是整型(ci的頂層const被忽略);
auto b=cr; //b是整型(cr的引用被忽略);
- auto如果我們希望推出的auto類型是頂層const,我們需要明确指出。例如:
,const int ci=2;
。const auto a=ci;
1.3 auto關鍵字與指針和引用
- 如果定義的對象是指針或者引用,則const屬性被保留。
- auto關鍵字與指針:設定類型為auto的指針,初始值的頂層const屬性仍然保留。
int i=2;
const int ci=i;
auto a=&i; //a是整型指針(整數的位址就是指向整數的指針);
auto b=&ci; //b是指向整型常量的指針(對const對象取位址是一種底層const);
//用auto聲明指針類型時,用auto和auto *沒有任何差別;
auto *pi=&i;
auto pi=&i; //兩種方式沒有差别;
//用auto聲明引用類型時則必須加&;
auto &ri=i; //ri為引用;
auto ri=i; //ri為int;
- auto關鍵字與引用:在使用auto關鍵字,使用引用其實是使用引用的對象。特别是當引用被用作初始值時,真正參與初始化的其實是引用的對象的值,此時編譯器以引用對象的類型作為auto的類型。另外設定類型為auto的引用,初始值的頂層const屬性仍然保留。例如:
int x = 0, &rx = x;
auto a1 = rx; //使用引用其實是使用引用的對象,
//此時auto以引用對象的類型作為auto的類型,
//是以auto這裡被推斷為 int;
auto &a2 = rx; //此時auto被推斷為int類型,a2本身就是int &類型;
const auto &a3 = rx;//auto被推斷為int類型,a3對象本身是const int &類型;
//不能通過a3去修改rx引用的對象值;
int i=2; const int ci=i;
auto &a=ci; //此時auto被推斷為const int類型,a本身就是const int &類型;
auto &b=42; //錯誤,不能為非const引用綁定字面值;
const auto &c=43; //正确,可以為const引用綁定字面值;
1.4 auto關鍵字與數組和函數
- 在一些情況下,數組的操作實際上是指針的操作。意味着适用數組作為一個auto變量的初始值時,推斷得到的類型是指針而非數組。例如:
int ia[]={1,2,3,4,5};
auto ia2(ia); //此時ia2是整型指針,指向ia的第一個元素,
//相當于auto ia2(&ia[0]);
decltype(ia) ia3={0,1,2,3,4}; //此時ia3是一個數組;
const char arr[] = "I Love China";
auto r1 = arr; //如果将數組名指派給auto變量,那麼auto推斷的結果是指針類型,
//如果有const屬性保留,
//auto推斷的結果是const char *;
auto &r2 = arr;// 如果将數組名指派給auto &變量,
//auto &變量的類型是一個數組引用類型,即為const char (&)[14];
int add(int a,int b); //函數聲明;
auto r3 = add; //r3為int(*)(int, int);
auto &r4 = add; //r4為int(&)(int, int);
1.5 auto關鍵字與使用new動态配置設定
- 如果使用括号包圍的初始化器,可以使用auto從初始化器中推斷想要配置設定對象的類型。隻有當括号僅有單一初始化器才能使用auto關鍵字。例如:
auto p1 = new auto (obj); //p1指向一個與obj類型相同的對象,該對象用obj進行初始化;
p1的類型是指針類型,指向從obj自動推斷出的類型;若obj是int,那麼p1就是int*。新配置設定的對象用obj的值進行初始化。auto p1 = new auto{a,b,c}; //錯誤,括号内隻能有單個初始化器;
1.6 auto關鍵字與使用的場景
- 适用的場景:
- 一些類型長度書寫很長的,可以用 auto 來簡化。例如
,如果使用auto可以直接寫為for(std::vector<int>::iterator it = v.begin();it != v.end();++it)
。for(auto it = v.begin();it != v.end();++it)
- 當函數傳回的值不确定時,可以用auto作為傳回值類型,更加友善。編譯器會根據傳回值的類型推斷 auto 的類型,這種文法是在 C++14 才出現的。例如:
auto func() { return 0; }
- 不适用的場景:
- 函數形參不能是auto類型,比如
是不允許的。int add(auto a, auto b) { return a + b; }
- 類的非static成員變量不可以是auto類型。類的static成員變量可以是auto類型的,但需要用const修飾,而且該變量需要類内初始化。例如:
。auto static const i=4;
- auto 不能直接用來聲明數組。
- 執行個體化模闆時不能使用auto作為模闆參數。
2.decltype關鍵字
2.1 decltype關鍵字作用
- C++11新标準引進decltype關鍵字,作用是選擇并傳回操作數的資料類型,在此過程中編譯器分析表達式并得到它的類型,卻不實際計算表達式的值。 例如
,編譯器實際上沒有調用fun函數,而是使用fun()的傳回值類型作為sum的資料類型。decltype關鍵字也是用來在編譯時推導出一個表達式的類型,但此表達式初始化與否在編譯器都沒有多大的影響。decltype(fun()) sum=x;
2.2 decltype關鍵字與頂層const和底層const
- decltype處理頂層const和引用的方式與auto有些不同,如果decltype使用的表達式是個變量,則decltype傳回該變量的類型(包括頂層const和引用在内)。例如:
const int ci=0,&cj=ci;
decltype(ci) x=0; //x的類型是const int;
decltype(cj) y=x; //y的類型是const int &,y綁定到變量x;
decltype(cj) z; //錯誤,z是引用,必須初始化;
//需要指出的是,引用從來都作為其所指對象的同義詞出現,
//隻有用在decltype處是例外情況;
2.3 decltype關鍵字與普通變量
- 對于非引用(指針),decltype關鍵字和auto關鍵字的作用類似,但是保留表達式的引用及const限定符,decltype能夠精确地推導出表達式定義本身的類型,不會像auto那樣在某些情況下舍棄掉引用和cv限定符。
2.4 decltype關鍵字與指針和引用
- 使用關鍵字decltype的時候,左值和右值有所不同。如果表達式的求值結果是左值,decltype作用于該表達式(不是變量)得到引用。例如,假定p的類型是
,因為解引用符生成左值,是以int*
的結果是decltype(*p)
;如果表達式的求值結果是右值,得到指向指針的指針,例如,int&
的結果是decltype(&p)
,因為取位址運算符生成右值。int**
- decltype與指針:decltype處理指針時需要保留指針,這點和auto是有差別。例如:
int tempA = 2;
int *ptrTempA = &tempA;
//1.正常使用dclTempA為一個int *的指針;
decltype(ptrTempA) dclTempA;
//2.需要特别注意,表達式内容為解引用操作,
//dclTempB為一個引用,引用必須初始化,故編譯不過;
decltype(*ptrTempA) dclTempB;
- decltype與引用:decltype處理引用時需要保留引用,這點和auto是有差別。例如:
//非const引用
int tempA = 0, &refTempA = tempA;
//1.dclTempA為引用,綁定到tempA;
decltype(refTempA) dclTempA = tempA;
//2.雙層括号表示引用,dclTempB為引用,綁定到tempA;
decltype((tempA)) dclTempB = tempA;
//const引用;
const int ctempA = 1, &crefTempA = ctempA;
//1.dclTempE為const用,可以綁定到非const變量;
decltype(crefTempA) dclTempE = tempA;
//2.dclTempF為const引用,可以綁定到const;
decltype(crefTempA) dclTempF = ctempA;
//3.dclTempG為const引用,綁定到一個字面值;
decltype(crefTempA) dclTempG = 0;
2.5 decltype關鍵字總結
- 下列給出decltype的各種用法:
//普通類型
decltype(func()) sum = 5; // sum的類型是函數func()的傳回值的類型int,
//但是這時不會實際調用函數func();
int a = 0;
decltype(a) b = 4; // a的類型是int, 是以b的類型也是int;
//不論是頂層const還是底層const, decltype都會保留;
const int c = 3;
decltype(c) d = c; // d的類型和c是一樣的, 都是頂層const;
int e = 4;
const int* f = &e; // f是底層const;
decltype(f) g = f; // g也是底層const;
//引用與指針類型
//1. 如果表達式是引用類型, 那麼decltype的類型也是引用;
const int i = 3, &j = i;
decltype(j) k = 5; // k的類型是 const int&;
//2. 如果表達式是引用類型, 但是想要得到這個引用所指向的類型, 需要修改表達式:
int i = 3, &r = i;
decltype(r + 0) t = 5; // 此時是int類型;
//3. 對指針的解引用操作傳回的是引用類型;
int i = 3, j = 6, *p = &i;
decltype(*p) c = j; // c是int&類型, c和j綁定在一起;
//4. 如果一個表達式的類型不是引用, 但是我們需要推斷出引用,
//那麼可以加上一對括号, 就變成了引用類型;
int i = 3;
decltype((i)) j = i; // 此時j的類型是int&類型, j和i綁定在了一起;
//解釋:如果decltype使用的是一個不加括号的變量,則得到結果就是該變量的類型;
//如果給變量加了一層或多層括号,編譯器就會當成一個表達式;
//decltype變量可以是指派語句左值的特殊表達式,這樣的decltype得到是引用類型;
//也就是decltype((var))的結果永遠是引用;
2.6 decltype關鍵字與decltype(auto)
- C++14新增的類型訓示符,可以用來聲明變量以及訓示函數傳回類型。在使用時,會将“=”号左邊的表達式替換掉auto,再根據decltype的文法規則來确定類型。
int e = 4;
const int* f = &e; //f是底層const;
decltype(auto) j = f; //j的類型是const int* 并且指向的是e;
2.7 decltype關鍵字與auto關鍵字差別
- decltype和auto都可以用來推斷類型,但是二者有幾處明顯的差異。
- auto忽略頂層const,decltype保留頂層const;
- 對引用操作,auto推斷出原有類型,decltype推斷出引用;
- 對解引用操作,auto推斷出原有類型,decltype推斷出引用;
- auto推斷時會實際執行,decltype不會執行,隻做分析。總之在使用中過程中和const、引用和指針結合時需要特别小心。
3.typeid關鍵字
3.1 typeid關鍵字作用
- typeid關鍵字的作用就是擷取一個表達式的類型。表達式可以是類型名稱、變量名、數字、字元串、指針、結構體等等,傳回結果是标準庫類型
對象的引用。在C++中,為了支援RTTI(運作時類型識别)提供了兩個操作符:type_info
和dynamic_cast
。typeid
3.2 typeid關鍵字類型識别和函數
- 如果表達式的類型是類類型且至少包含有一個虛函數,則typeid操作符傳回表達式的動态類型,需要在運作時計算;否則typeid操作符傳回表達式的靜态類型,在編譯時就可以計算。
-
如果兩個對象t1和t2類型相同,則傳回true;否則傳回false。t1==t2
如果兩個對象t1和t2類型不同,則傳回true;否則傳回false。t1!=t2
傳回類型的C-style字元串,類型名字用系統相關的方法産生。t.name()
傳回指出t1是否出現在t2之前的bool值。t1.before(t2)
-
類提供了public虛析構函數,以使使用者能夠用其作為基類。它的預設構造函數和拷貝構造函數及指派操作符都定義為private,是以不能定義或複制type_info類型的對象,程式中建立type_info對象的唯一方法是使用typeid操作符。type_info
3.3 typeid關鍵字與類對象
- 不帶虛函數的基類:
class base{
public:
void m(){cout<<"base"<<endl;}
};
class derived : public base{
public:
void m(){cout<<"derived"<<endl;}
};
假設定義如下指針:
base * p = new derived;
,下表将給出使用typeid操作符的結果。
typeid(p) == typeid(base*); //true
typeid(p) == typeid(derived*); //false
typeid(*p) == typeid(base); //true
typeid(*p) == typeid(derived); //false
//對于表達式typeid(p),因為p是base*類型的指針,
//是以typeid(p)==typeid(base*)為真,
//而typeid(p)==typeid(derived*)為假;
//而對于表達式typeid(*p),由于此時的基類不具有多态性;
//因而*p将會采用編譯期類型來計算,編譯期*p是base對象,
//是以表達式typeid(*p) == typeid(derived)為假,
//typeid(*p) == typeid(base)為真;
- 帶虛函數的基類:
class base{
public:
virtual void m(){cout<<"base"<<endl;}
};
class derived : public base{
public:
void m(){cout<<"derived"<<endl;}
};
假設定義指針如下:
base * p = new derived;
下面給出使用typeid操作符的結果。
typeid(p) == typeid(base*); //true
typeid(p) == typeid(derived*); //false
typeid(*p) == typeid(base); //false
typeid(*p) == typeid(derived); //true
//對于表達式typeid(p),因為p是base*類型的指針,
//是以typeid(p) == typeid(base*)為真,
//而typeid(p) == typeid(derived*)為假;
//而對于表達式typeid(*p),因為base類具有多态性,
//因而在計算typeid(*p)時會根據運作時p所指向的實際類型去計算,
//而本例中p指向的是派生類對象,
//是以表達式typeid(*p) == typeid(derived)為真,
//typeid(*p) == typeid(base)為假;
4.initializer_list關鍵字
4.1 initializer_list關鍵字作用
- C++11提供了initailzer_list的關鍵字,如果所有的實參類型相同,可以傳遞一個名為initailzer_list的标準庫類型。
4.2 initializer_list關鍵字與vector差別
- initialzer_list對象中的元素永遠是const,我們無法改變initialzer_list對象中元素的值。
4.3 initializer_list關鍵字提供的操作
-
initialzer_list<T> lst;//預設初始化,T類型元素的空清單;
-
initialzer_list<T> lst{a,b,c....};//lst的元素數量和初始化一樣多,lst的元素是對應初始值的副本,清單中的元素是const;
-
lst2(lst);//或者lst2=lst;拷貝或者指派一個initialzer_list對象不會拷貝清單中的元素;拷貝後,原始清單和副本共享元素;
-
lst.size();//清單中元素的數量;
-
lst.begin();//傳回指向lst中首元素的指針;
-
。lst.end();//傳回指向lst中尾元素下一位置的指針
5.explicit關鍵字
- 類與對象這篇文章有相關介紹。