關鍵字typedef、關鍵字using、auto類型說明符和declytpe類型指示符

文章目錄

  • 類型別名
    • 概念
    • 關鍵字 typedef
    • 別名聲明 (alias declaration) using
    • 指針、常量和類型別名
    • 類型別名簡化多維數組指針
  • auto類型說明符
    • 概念
    • 復合類型、常量和auto
  • decltype類型指示符
    • 概念
    • decltype和引用


類型別名

概念

有兩種方法可用于定義類型別名。

關鍵字 typedef

typedef double wages; // wages是double的同義詞
typedef wages base, *p; // base是double的同義詞,p是double*的同義詞

關鍵字typedef作為聲明語句中的基本數據類型的一部分出現。含有typedef的聲明語句定義的不再是變量而是類型別名。這和以前的聲明語句一樣,這里的聲明符也可以包含類型修飾,從而也能由基本數據類型構造出復合類型來。

別名聲明 (alias declaration) using

using SI = Sales_item; // SI是Sale_item的同義詞

這種方法用關鍵字using作為別名聲明的開始,其后緊跟別名和等號,作用是把等號左側的名字規定成等號右側類型的別名。

類型別名和類型的名字等價,只要是類型的名字能出現的地方,就能使用類型別名:

wages hourly, weekly; // 等價于double hourly, weekly;
SI item; // 等價于Sales_item item

指針、常量和類型別名

如果某個類型別名指代的是復合類型或常量,那么把它用到聲明語句里就會產生意想不到的后果。

typedef char *pstring;
const  pstring cstr = 0; // cstr是指向char的常量指針
const pstring *ps; // ps是一個指針,它的對象是指向char的常量指針

上述兩條聲明語句的基本類型都是const pstring,const是對給定類型的修飾。pstring實際上是指向char的指針,const pstring則是指向char的常量指針,而非指向常量字符的指針。

也就是說,遇到一條使用了類型別名的聲明語句時,把類型別名直接替換成它本來的樣子是錯誤的:

const char *cstr = 0; // 是對const pstring cstr的錯誤理解

聲明語句中用到pstring時,其基本數據類型是指針。使用char*重寫了聲明語句后,數據類型就變成了char,*成為了聲明符的一部分。上述改寫的結果是,const char成了基本數據類型。前后兩種聲明含義截然不同,前者聲明了一個指向char的常量指針,改寫后的形式則聲明了一個指向const char的指針。


類型別名簡化多維數組指針

typedef int int_array[4];
int main()
{int ia[3][4] = {};for (int_array *p = ia; p != ia+3; ++p) {for(int *q = *p; q != *p + 4; ++q){std::cout << *q << ' ';}cout << endl;}
}

具體對這個語句來說,別名就是:int_array。[4]不屬于別名的一部分,而表示一種已有的數據類型,即:將類型“4個整數組成的數組”取一個別名為int_array。

怎么理解呢?首先,

int ia[4];

是常見的定義格式。再在其前面添加關鍵字 typedef,變成

typedef int ia[4];

最后將數組名ia改為自己想要的一個別名int_array即可。

注意:原本的ia本意是數組名,屬于變量范疇,而int_array則是新數據類型名(即別名),類型為int[4],本質不一樣了哦。



auto類型說明符

概念

C++11新標準引入了auto類型說明符,能讓編譯器替我們去分析表達式所屬的類型。和原來那些只對應一種特定類型的說明符(int、double等)不同,auto讓編譯器通過初始值來推算變量的類型。auto定義的變量必須有初始值:

// 由val1和val2相加的結果可以推斷出item的類型
auto item = val1 + val2;

val1和val2兩個變量的類型如果是double,則item也是double,如果兩個變量是int,則item也是int,以此類推。

當然也允許在一條語句中聲明多個變量。因為一條聲明語句只能有一個基本數據類型,所以該語句中所有變量的初始基本數據類型必須都一樣:

auto i = 0, *p = &i; // 正確:i是整數、p是整型指針
auto sz = 0, pi = 3.14; // 錯誤:sz和pi的類型不一樣

復合類型、常量和auto

編譯器推斷出來的auto類型有時候和初始值的類型并不完全一樣,編譯器會適當地改變結果類型使其更符合初始化規則。

  1. 當引用被用作初始值時,編譯器以引用對象地類型作為auto的類型:
int i = 0, &r = i;
auto a = r; // a是一個整數(因為i是一個整數)
  1. auto一般會忽略掉頂層const,同時底層const則會保留下來:
const int ci = i, &cr = ci;
auto b = ci; // b是一個整數(ci的頂層const特性被忽略)
auto c = cr; // c是一個整數(同上)
auto d = &i; // d是一個整型指針(整數的地址就是指向整數的指針)
auto e = &ci; // e是一個指向整數常量的指針(對常量對象取地址是一種底層const)
  1. 如果希望推斷出的auto類型是一個頂層const,需要明確指出:
const auto f = ci; // ci的推演類型是int,f 是const int
  1. 還可以將引用的類型設為auto,此時原來的初始化規則仍然適用:
auto &g = ci; // g是一個整型常量引用,綁定到ci
auto &h = 42// 錯誤:不能為非常量引用綁定字面值
const auto &j = 42// 正確:可以為常量引用綁定字面值

設置一個類型為auto的引用時,初始中的頂層常量屬性仍然保留,也就是常量對象依然必須由常量引用綁定。 如果給初始值綁定一個普通引用,此時的常量就不是頂層常量了(由于引用不是對象,因此對于引用而言變成了底層const,依然是會忽略頂層const的毛病)。

  1. 要在一條語句中定義多個變量,切記,符號&和*只從屬于某個聲明符,而非基本數據類型的一部分,因此初始值必須是同一種類型:
auto k = ci, &l = i; // k是整數,l是整型引用
auto &m = ci, *p = &ci; // m是對整型常量的引用,p是指向整型常量的指針
auto &n = i, *p2 = &ci; // 錯誤:i的類型是int而&ci的類型是const int
  1. auto可以與指針和引用結合
int main()
{int i = 4;auto a1 = &i;auto *a2 = &i;auto& a3 = i;cout <<"a1的類型為:" << typeid(a1).name() << endl;cout << "a2的類型為:" << typeid(a2).name() << endl;cout << "a3的類型為:" << typeid(a3).name() << endl;
}

在這里插入圖片描述
因為auto可以識別指針類型,所以加不加*都可以,但是引用必須加上&,因為C++沒有引用這個類型,引用只是一個修飾別名,所以它的本質還是int。

  1. auto不能作為函數的參數

在這里插入圖片描述
auto不能作為形參的類型,編譯器無法對i和j的類型進行推導。

8.auto不能直接用來聲明數組
在這里插入圖片描述



decltype類型指示符

概念

有時會希望從表達式的類型推斷出要定義的變量的類型,但是不想用該表達式的值初始化變量,因此也就不能用auto類型說明符。為了滿足這一要求,新標準引入了第二種類型說明符decltype,它的作用是選擇并返回操作數的數據類型。在此過程中,編譯器分析表達式并得到它的類型,卻不實際計算表達式的值:

decltype(f()) sum = x; // sum的類型就是函數f的返回類型

編譯器并不實際調用函數f,而是使用當調用發生時 f 的返回值類型作為sum的類型。換句話說,編譯器為sum指定的類型是假如 f 被調用的話將會返回的那個類型。

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是一個引用,必須初始化

因為cj是一個引用,decltype(cj)的結果就是引用類型,因此作為引用的z必須被初始化。

引用從來都是作為其所指對象的同義詞出現,只有在decltype處是一個例外。


decltype和引用

如果decltype使用的表達式不是一個變量,則decltype返回表達式結果對應的類型。有些表達式將向decltype返回一個引用類型。當這種情況發生時,意味著該表達式的結果對象能作為一條賦值語句的左值:

int i = 42, *p =&i, &r = i;
decltype(r+0) b; // 正確:加法的結果是int,因此b是一個(未初始化的)int
decltype(*p) c; // 錯誤:c是int&,必須初始化

因為r是一個引用,因此decltype?的結果是引用類型。如果想讓結果類型是 r 所指的類型,可以把 r 作為表達式的一部分,如 r+0,顯然這個表達式的結果將是一個具體值而非一個引用。

另一方面,如果表達式的內容是解引用操作,則decltype將得到引用類型。解引用指針可以得到指針所指的對象,而且還能給這個對象賦值。因此,decltype(*p)的結果就是int&,而非int。

decltype和auto的另一處重要區別是,decltype的結果類型與表達式形式密切相關。 對于decltype所用的表達式來說,如果變量名加上了一對括號,則得到的類型與不加括號時會有不同。如果declytpe使用的是一個不加括號的變量,則得到的結果就是該變量的類型;如果給變量加上一層或多層括號,編譯器就會把它當成一個表達式。 變量是一種可以作為賦值語句左值的特殊表達式,所以這樣的decltype就會得到引用類型:

// decltype的表達式如果是加上了括號的變量,結果將是引用
decltype((i)) d; // 錯誤:d是int&,必須初始化
decltype(i) e; // 正確:e是一個(未初始化的)int

declytpe((variable))的結果永遠是引用,而declytpe(variable)結果只有當variable本身就是一個引用時才是引用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/443837.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/443837.shtml
英文地址,請注明出處:http://en.pswp.cn/news/443837.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

初始化、賦值、默認初始化、列表初始化、類內初始值、直接初始化與拷貝初始化

文章目錄初始化和賦值的區別什么是默認初始化&#xff1f;列表初始化列表初始化的使用場景不適合使用列表初始化的場景類內初始值混用string對象和C風格字符串數組與vector對象關于vector對象兩者間的初始化關系直接初始化與拷貝初始化初始化和賦值的區別 初始化的含義是創建變…

js動態增加,刪除td,tr,table,div

js實現的動態添加&#xff0c;刪除table內容&#xff1a; 截圖如下&#xff1a; 1. 2. 源代碼&#xff1a; main.css body {background-image: url(../images/qiantai/bg.png);font-family: arial;font-size: 12px;color: #d4d7da;text-align: center;background-repeat: r…

string類的相關知識及部分操作

文章目錄string對象的初始化string::size_type類型string對象的讀寫操作使用標準庫中的iostream使用getline讀取一整行string對象的比較操作string對象的相加操作兩個string對象相加字面值和string對象相加string對象的初始化 拷貝初始化(copy initialization)&#xff1a;使用…

數組的部分練習

3.27&#xff1a;假設txt_size是一個無參數的函數&#xff0c;它的返回值是int。請回答下列哪個定義是非法的&#xff1f;為什么&#xff1f; unsigned buf_size1024; &#xff08;a&#xff09;int ia[buf_size];  &#xff08;b&#xff09;int ia[4*7-14]; &#xff08…

關于范圍for語句的使用

文章目錄使用范圍for語句處理多維數組使用范圍for語句處理多維數組 舉個例子&#xff0c;使用范圍for語句輸出多維數組&#xff08;ia&#xff09;所有值&#xff1a; for (const auto &row : ia)for (auto col : row)cout << col << endl;本循環中并沒有任何…

vector的應用練習

文章目錄編寫一段程序&#xff0c;使用條件運算符從vector< int >中找出哪些元素的值是奇數&#xff0c;然后將奇數值翻倍。 #include <iostream> #include <ctime> #include <vector> using namespace std; typedef int int_array[4]; int main() {v…

sizeof運算符運算結果小匯

文章目錄sizeof運算符的結果部分地依賴于其作用的類型sizeof運算符的結果部分地依賴于其作用的類型 對char或者類型為char的表達式執行sizeof運算&#xff0c;結果得1對引用類型執行sizeof運算得到被引用對象所占空間的大小對指針執行sizeof運算得到指針本身所占空間的大小對解…

jQuery實現復選框的全選和反選:

jQuery實現復選框的全選和反選&#xff1a; 截圖如下&#xff1a; 代碼如下&#xff1a; index.jsp: <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <%String path request.getContextPath();String basePath…

C語言隱式/顯式類型轉換 | C++四種強制類型轉換、類的隱式轉換、explicit

文章目錄C語言類型轉換隱式類型轉換顯式類型轉換C 強制類型轉換static_castreinterpret_castconst_castdynamic_cast類的隱式類型轉換概念只允許一步類類型轉換explicit 抑制構造函數定義地隱式轉換可以通過顯式轉換使用explicit構造函數C語言類型轉換 隱式類型轉換 編譯器在…

string對象和C風格字符串

混用string對象和C風格字符串 我們都知道允許使用字符串字面值來初始化string對象&#xff1a; string s("Hello World!");C規定&#xff0c;任何出現字符串字面值的地方都可以用以空字符結束的字符數組來替代&#xff1a; 允許使用以空字符結束的字符數組來初始化…

函數重載、引用再探、內聯函數

文章目錄函數重載為什么C支持重載&#xff0c;C語言不支持呢&#xff1f;extern “C”引用再探引用的特性引用的使用場景引用和指針引用和指針的不同點:內聯函數什么是內聯函數&#xff1f;內聯函數的特性內聯函數的好處類的內聯成員函數的聲明內聯函數的使用constexpr函數概念…

類的概念、成員函數的定義方式、類的訪問控制和封裝、類的大小、this指針

文章目錄類的概念structclassclass和struct的區別是什么呢&#xff1f;類中成員函數的兩種定義方式聲明和定義都在類中聲明和定義分離類的訪問控制和封裝類的封裝特性類的大小結構體內存對齊規則類的存儲方式this指針類的概念 在C中&#xff0c;類可以說是最重要的東西&#x…

jQuery實現兩個列表框的值之間的互換:

jQuery實現兩個列表框的值之間的互換&#xff1a; 截圖如下&#xff1a; 代碼如下&#xff1a; <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <%String path request.getContextPath();String basePath reque…

類的6個默認成員函數:構造函數、析構函數、拷貝構造函數、重載運算符、三/五法則

文章目錄6個默認成員函數構造函數概念默認構造函數的類型默認實參概念默認實參的使用默認實參聲明全局變量作為默認實參某些類不能依賴于編譯器合成的默認構造函數第一個原因第二個原因第三個原因構造函數初始化構造函數里面的“”是初始化嗎&#xff1f;為什么要使用列表初始化…

C++ 類的知識 | 構造函數再探、匿名對象、友元函數、內部類、類的const成員、類的static成員

文章目錄構造函數再探以下代碼共調用多少次拷貝構造函數委托構造函數概念形式匿名對象友元友元的聲明友元類令成員函數作為友元函數重載和友元注意內部類特性類的const成員可變數據成員類的static成員概念關于static靜態成員的類內初始化靜態成員能用于某些普通成員不能的場景構…

截取全部數值字符并將其轉化為數值類型

功能 從name中找出全部數值字符&#xff0c;之后將name&#xff08;string類&#xff09;轉為d&#xff08;double類&#xff09; 代碼 #include <iostream> #include <list> #include <deque> #include <vector> #include <forward_list> #i…

替換string中的部分字符

功能 向函數fun中傳入三個參數&#xff1a;將s中所有oldval替換為newval 代碼 #include <iostream> #include <list> #include <deque> #include <vector> #include <forward_list> #include <array> using namespace std;void fun(str…

順序容器(vector、list、string、deque、forward_list)及迭代器、容器適配器

文章目錄概述所有容器都支持的操作迭代器迭代器支持的操作迭代器支持的算術運算容器類型size_typeiterator 和 const_iterator容器定義和初始化拷貝初始化順序容器獨有的構造函數&#xff08;array除外&#xff09;array的初始化與內置數組類型的區別6種初始化方法&#xff08;…

jQuery實現表格隔行換顏色:

jQuery實現表格各行換顏色&#xff1a; 截圖如下&#xff1a; 代碼如下&#xff1a; <span style"font-family:Microsoft YaHei;font-size:14px;"><% page language"java" import"java.util.*" pageEncoding"UTF-8"%> &…

用stack處理中綴表達式【+、-、*、/、()】

文章目錄題目描述思路使用getline()存儲輸入的字符串邊讀取邊壓棧完整代碼題目描述 使用stack處理括號化的表達式。當你看到一個左括號&#xff0c;將其記錄下來。當你在一個左括號之后看到一個右括號&#xff0c;從stack中pop對象&#xff0c;直至遇到左括號&#xff0c;將左括…