C++ Primer 第二章 學習筆記及習題答案

Camelia發表於2019-05-14

知識點

基本內建型別

  • 算數型別:整型(包括布林型和字元型)、浮點型、空型別。
  • 空型別:不對應任何值,常用來當函式不返回任何值時使用空型別作為返回型別。
  • 帶符號型別和無符號型別:帶符號型別可以表示正數、負數、0;無符號型別僅可表示大於等於0的值。
  • 選擇型別的經驗:
    1 當明確知曉數值不可能為負時,選用無符號型別。
    2 使用int執行整數運算,如果溢位,則使用long long。
    3 在算術表示式中不使用char或bool型別,僅在存放字元或布林值時才使用它們。
    4 執行浮點運算時選用double。

型別轉換規則

  • 非布林轉布林型:值為0,轉為False,否則為True;
  • 布林轉非布林型:值為False,轉為0,值為True,轉為1;
  • 浮點型轉整型:做近似處理,僅保留小數點之前部分;
  • 整型轉浮點型:小數部分記為0;
  • 當賦一個超出其範圍的值給無符號型別時,結果為初始值對無符號型別表示數字總數取模後的餘數;
  • 當給帶符號型別賦超過其表示範圍的數值時,其結果是未定義的,可能導致程式崩潰。
  • 請勿混用帶符號型別和無符號型別:當表示式中既有帶符號型別又有無符號型別時,帶符號數會自動轉換成無符號數。

字面值常量

  • 整型字面值

    • 形式:

      • 八進位制:以0開頭
      • 十進位制:正常表示
      • 十六進位制:以0x開頭
    • 整型字面值可以有字尾:

      • u或U對應unsigned;
      • l或L對應long;
      • ll或LL對應long long。
  • 浮點型字面值(預設double)

    • 形式:

      • 小數:如3.14159 .001
      • 科學計數法:指數部分用E或e標識,如0. 0e0 3.14159E0
    • 浮點型字面值可以有字尾:

      • f或F對應float;
      • l或L對應long double。
  • 字元和字串字面值

    • 形式:

      • 字元字面值:用單引號括起來,`a`
      • 字串字面值:用雙引號括起來,”abc”
      • 注意:字串字面值實際上是由常量字元構成的陣列,在每個字串結尾處新增空字元` `,字串字面值的實際長度比它的內容多1
    • 字元和字串字面值可以有字首:

      • u表示Unicode16字元
      • U表示Unicode32字元
      • L表示寬字元
      • u8表示UTF-8(僅用於字串字面常量)
  • 不能直接使用的字元:

    • 形式:

      • 不可列印的字元,如退格等控制字元,因為沒有可視的圖符
      • 轉義序列:以反斜槓開始
      • 泛化轉移序列:

        • 反斜槓後緊跟1~3個數字
        • 反斜槓x後緊跟一個或多個八進位制數字
  • 布林字面值和指標字面值

    • true和false是布林型別的字面值;
    • nullptr是指標字面值

變數

  • 定義形式:型別說明符 一個或多個變數名組成的列表,如int a; int a,b;
  • 初始值:物件在建立時獲得的一個特定的值,一旦定義即可馬上使用 (在同一條定義語句中,也可以用先定義的變數值去初始化後定義的變數)
  • 列表初始化的4種方式:

    • int units_sold = 0;
    • int units_sold = {0};
    • int units_sold{0};
    • int units_sold(0);
  • 預設初始化:在定義變數時沒有指定初值,變數被預設初始化。若內建型別的變數未被顯示初始化,則它的值是由定義的位置決定的。定義於任何函式體之外的變數初始化為0;在函式體內部的變數不被初始化(即值未定義),在拷貝或訪問此類值時將引發錯誤。因此,建議初始化每一個內建型別的變數。
  • 宣告和定義:為了支援分離式編譯(separate compilation),C++將宣告和定義區分。宣告使得名字為程式所知,一個檔案如果想使用別處定義的名字則必須包含對那個名字的宣告。定義負責建立與名字關聯的實體。變數的宣告和定義都規定了變數的型別和名字,但是定義還可以申請儲存空間,也可能為變數賦初值。

    • 宣告extern:extern int i;
    • 定義:int j;
    • 顯式化的宣告即為定義:extern double pi = 3.14159: //定義
    • 變數能且只能定義一次,但是可以被多次宣告
    • 在變數第一次被使用的附近定義它
    • 一條宣告語句由一個基本資料型別和一個宣告符列表組成。
  • 變數命名規範:由字母、數字和下劃線組成,必須以字母或下劃線開頭。

    • 識別符號要體現實際含義
    • 變數名一般用小寫字母
    • 使用者自定義的類名一般以大寫字母開頭
    • 如果識別符號由多個單片語成,單詞間應該有明顯區分(下劃線或首字母大寫)
  • 作用域:以花括號{ }分額

    • 外層作用域的變數內層可見
    • 全域性作用域所有可見

指標、引用、const

引用

  • 引用為物件起了別名,在定義引用時,程式將引用和它的初始值繫結(bind),一旦初始化完成,引用和它的初始化物件一直繫結在一起,因此引用必須初始化
  • 定義: int i = 1024; int &r = i;

指標

  • 指標實現對其他物件的間接訪問,指標記憶體放著某個物件的地址。建議初始化所有指標
  • 定義:

    • int *p1;
    • 獲取物件的地址:int ival = 42; int *p2 = &ival;
    • 解引用*:如果指標指向了一個物件,可以使用解引用操作符*來訪問指標指向的物件
    • 空指標: int *p3 = nullptr;
  • 辨析*p 和 p:*p是指標所指的物件,p是指標所指的物件的地址值。

指標和引用的區別(補充)

  • 指標本身是一個物件,引用只是物件的別名
  • 指標在其生命週期內可以先後指向不同的物件,引用在初始化完成後,即和它的初始化物件繫結在一起。
  • 指標無需在定義時賦初值,引用必須初始化。

指向引用的指標和指標的引用

  • 指標的引用:指標必須指向一個物件,引用不是物件,故指標的引用不存在
  • 指向引用的指標:

    int i = 42; 
    int &r = i; 
    int *p; 
    int *&r= p; // r為對指標p的引用

const

  • const物件必須初始化,一旦建立後其值就不能再改變
  • const物件以初始化的方式定義時,在編譯過程中把用到該const變數的地方都替換成對應的值。
  • 預設狀態下,const物件僅在檔案內有效,如果想在多個檔案之間共享const物件,必須在變數的定義之前新增extern(宣告)。
  • 定義:
 int const i = 42;         //編譯時初始化
 int const j = get_size(); //執行時初始化

const的引用

  • 對常量的引用簡稱常量引用,在初始化常量引用時允許用任意表示式作為初始值,允許為一個常量引用繫結非常量的物件、字面值、一般表示式。
  • 常量引用不允許通過引用修改其繫結物件的值,但可以通過其他途徑修改其繫結物件的值(直接修改繫結物件的值,通過其他非常量引用修改等)。

指向常量的指標和常量指標

  • 指向常量的指標:指標指向的物件的值不能變(*p不能變)
  • 常量指標:指標的值(指標記憶體放的地址不能變)(p不能變)const指標本質是一個const物件,const物件必須初始化
  • 定義:從右向左閱讀

    • 指向常量的指標:const int p; int const p;
    • 常量指標:int *const p;

頂層const和底層const

  • 定義

    • 頂層const(top-level const):指標本身是個常量
    • 底層const(low-level const):指標所指的物件是個常量
  • 執行物件的拷貝操作時:

    • 1)頂層const不受影響
    • 2)對於底層const而言:

      • 拷入和拷出的物件必須具有相同的底層const資格
      • 兩個物件的資料型別必須能夠轉換。一般來說,非常量可以轉換為常量,反之則不行。
  • 用於宣告引用的const都是底層const

constexpr(常量表示式)

  • 定義:值不會改變並且在編譯過程就能得到計算結果的表示式。(在編譯時運算,直接儲存計算結果)
  • constexpr所定義的物件為頂層const。

型別別名

  • 定義型別別名的兩種方法:

    • typedef: typedef double wages; //wages等同於double
    • 別名宣告(alias declaration):using SI = Sales_item; //SI等同於Sales_item
  • 在複合型別或常量中,在定義了別名後不要試圖替換為本來的樣子進行理解會造成錯誤。

auto和decltype

  • auto:讓編譯器代替分析表示式所屬的型別。通過初始值推算變數型別

    • auto會忽略引用和頂層const,保留底層const
    • 在一條語句內定義多個變數時,初始值必須為同一型別
  • decltype:在不用表示式的值初始化變數的情況下,從表示式的型別推斷出要定義的變數的型別。編譯器分析表示式並得到他的型別,卻不實際計算表示式的值

練習題

2.1節練習

2.1.1節練習

  • 練習2.1:型別int、long、long long和short的區別是什麼?無符號型別和帶符號型別的區別是什麼?float和double的區別是什麼?

           (1)int和short型別最小尺寸為16位,long型別為32位,long long型別為64位。
           (2)無符號型別僅可表示大於0的數值,帶符號型別可以表示正數、負數、0。(char型別中,unsigned char與char不相等)
           (3)float為單精度浮點型別,double為雙精度浮點型別,通常float和double以16位和32位來表示,且float和double分別具有7和16個有效位。
  • 練習2.2:計算按揭貸款時,對於利率、本金和付款分別應選擇何種資料型別?說明你的理由。
    利率和本金應選擇double型別,因為利率和本金有小數。付款方式選擇字元型。

2.1.2節練習

  • 練習2.3:讀程式寫結果。

    unsigned u = 10, u2 = 42;
    std::cout << u2 - u << std::endl;    //輸出32
    std::cout << u - u2 << std::endl;    //輸出u所佔位數的值的模-32    
    
    int i = 0, i2 = 42;
    std::cout << i2 - i << std::endl;    //輸出42
    std::cout << i - i2 << std::endl;    //輸出-42
    std::cout << i - u << std::endl;     //輸出u所佔位數的值的模-10
    std::cout << u - i << std::endl;     //10
  • 練習2.4:編寫程式檢查你的估計是否正確,如果不正確,請仔細研讀本節直到弄明白問題所在。

2.1.3節練習

  • 練習2.5:指出下述字面值的資料型別並說明每一組內幾種字面值的區別:

    (a)`a`, L`a`, "a", L"a" 
    (b)10, 10u, 10L, 10uL, 012, 0xC
    (c)3.14, 3.14f, 3.14L
    (d)10, 10u, 10., 10e-2
    
     (a)`a`:字元型,字面值為a,
         L`a`:寬字面字元型 ,字面值為a
         "a":字串型,字面值為a
         L"a" :寬字面字串型,字面值為a
    (b)10:整型,字面值為10
       10u:無符號整型,字面值為10
       10L: 長整型,字面值為10
       10uL:無符號長整型,字面值為10
       012:八進位制整型,字面值為八進位制的12
       0xC:十六進位制整型,字面值為十六進位制的C
    (c)3.14:double型,字面值為3.14
       3.14f:float型,字面值為3.14
       3.14L:long double型,字面值為3.14
    (d)10:整型,字面值為10
       10u:無符號整型,字面值為10
       10.: 浮點(double)型,字面值為10.
       10e-2: 浮點(double)型,科學計數法表示,字面值為10e-2(即0.01)
    
  • 練習2.6:下面兩組定義是否有區別,如果有,請敘述之:

    int month = 9, day = 7;
    int month=09, day = 07;
    
    答:有區別,第一行定義的month和day為十進位制的整型,第二行定義的month和day為八進位制的整型。
  • 練習2.7:下面字面值表示何種含義?他們各自的資料型別是什麼?

    (a)"Who goes with F145rgus? 12"
    (b)3.14e1L            (c)1024f        (d)3.14L
    
    (a)字串型,字面值為"Who goes with Fergus?"(注意:\145為八進位制數泛化轉義,\0為字串結束標誌符,後面的12不列印) 
    (b)long double型別,利用科學計數法表示,字面值為3.14
    (c)float型別,字面值為1024
    (d)long double型別,字面值為3.14
  • 練習2.8:請利用轉義序列編寫一段程式,要求先輸出2M,然後轉到新一行。修改程式使其先輸出2,然後輸出製表符,再輸出M,最後轉到新一行。

    int main()
    {
        std::cout <<"2115
    " << std::endl;
        std::cout << "2	115
    " << std::endl;
        return 0;
    }

2.2節練習

2.2.1節練習

  • 練習2.9:解釋下列定義的含義。對於非法的定義,請說明在何處並將其改正。

    (a) std::cin >> int input_value;                    (b) int i = { 3.14 };
    (c) double salary = wage = 9999.99;                 (d) int i = 3.14;
    
    (a) 變數需先定義再使用,應改為:
        int input_value = 0; //初始化變數防止未知錯誤
        std::cin >> input_value;
    (b) int為整型,3.14為浮點型,型別不匹配,需要型別轉換(此處未自動進行型別轉換),應改為:
        double i ={3.14};
    (c) 定義方式錯誤,應該為 double salary wage = 9999.99;
    (d) int為整型,3.14為浮點型,型別不匹配,需要型別轉換(此處自動進行型別轉換),i字面值儲存為3,若要保留小數點後應改為:
        double i ={3.14};
  • 練習2.10:下列變數的初值分別是什麼?

        std::string global_str;
        int global_int;
        int main()
        {
            int local_int;
            std::string local_str;
        }
    
    global_str和global int在所有函式體之外,故global_str初始值為" ",global_int初始值為0
    local_str和local_int在函式體內部,不被初始化,變數值為定義    

2.2.2節練習

  • 練習2.11:指出下面的語句是宣告還是定義:

        (a) extern int ix =1024;
        (b) int iy;
        (c) extern int iz;
    
        (a) 顯式化的宣告即為定義,賦值抵消了extern的作用。
        (b) 定義            (c) 宣告

2.2.3節練習

  • 練習2.12:請指出下面的名字中那些是非法的?

    (a) int double = 3.14;                (b) int _;
    (c) int catch-22;                    (d) int 1_or_2 = 1;
    (e) double Double = 3.14;
    
    (a) 非法,double為型別名
    (b) 正確                            
    (c) 錯誤,識別符號只能由字母、數字、下劃線組成
    (d) 錯誤,識別符號以字母或下劃線開頭,不能以數字開頭
    (e) 正確

2.2.4節練習

  • 練習2.13:下面程式中j的值是多少?

        int i = 42;
        int main()
        {
            int i = 100;
            int j = i;
        }
    
    j的值為100;i為全域性變數,但在main函式中i為內層變數值為100,並且將i的值賦給了j,所以j中儲存的值為100。
  • 練習2.14:下面的程式合法嗎?如果合法,它將輸出什麼?

        int i = 100, sum = 0;
        for (int i = 0; i != 10; i++)
            sum += i;
        std::cout << i << " " << sum << std::endl;
    
        合法;輸出i的值為100,sum的值為45。

2.3節練習

2.3.1節練習

  • 練習2.15:下面的哪個定義是不合法的?為什麼?

    (a) int ival = 1.01;        (b) int &rvall = 1.01;
    (c) int &rval2 = ival;      (d) int &rval3;
    
    (a) 非法,此處引用型別的初始值必須是物件       
    (b) 非法,此處引用型別的初始值必須是int型物件
    (c) 正確
    (d) 非法,引用必須初始化
  • 練習2.16:考查下面的所有賦值然後回答:哪些賦值是不合法的?為什麼?哪些賦值時合法的?他們執行了什麼樣的操作?

    int i = 0, &r1 = i;        double d = 0, &r2 = d;
    (a) r2 = 3.14159;          (b) r2 =r1;
    (c) i =r2;                 (d) r1 = d;
    
    (a) 正確,引用只是別名,相當於d=3.14159        
    (b) 正確,相當於d = i
    (c) 正確,相當於i = d                
    (d) 正確,相當於i = d
  • 練習2.17:執行下面的程式碼段將輸出什麼結果?

    int i, &ri = i;
    i = 5; ri = 10;
    std::cout << i << " " << ri << std::endl;
    
    輸出 10 10;
    引用只是別名;初始化完成後,更改ri的值i的值也會更改。

2.3.2節練習

  • 練習2.18:編寫程式碼分別更改指標的值以及指標所指物件的值。

    int main() {
    int i = 26, j = 24;
    int *p = &i;
    p = &j;        //改變指標的值
    *p = 25;    //改變指標所指物件的值

}

- 練習2.19:說明指標和引用的區別。
   見上面筆記,還沒補充完整。
  • 練習2.20:請敘述下面這段程式碼的作用。

    int i = 42;
    int *p1 = &i;     // 將指標p1指向i,p1中為i的地址值,*p1為i的值即42。
    *p1 = *p1 * *p1;  // 將指標p1指向的物件值變為42×42,即p1現在所指的物件值為1764。
  • 練習2.21:請解釋下述定義。在這些定義中有非法的嗎?如果有,為什麼?

    int i = 0;
    (a) double* dp = &i;        (b) int *ip = i;        (c) int *p = &i;
    (a) 非法,指標型別為double,指標所指物件型別不匹配
    (b) 非法,指標存放的是地址值,i不是地址值        
    (c) 正確,常規定義方法。
  • 練習2.22:假設p是一個int型指標,請說明下述程式碼的含義。

    if (p)    // 如果指標存放的地址值為空,則為false,不為空則為true
    if (*p)   // 如果指標指向的物件值為0,則為false,不為0則為true
    
  • 練習2.23:給定指標p,你能知道它是否指向了一個合法的物件嗎?如果能,敘述判斷的思路;如果不能,也請說明原因。

    不能?????
  • 練習2.24:在下面這段程式碼中為什麼p合法而lp不合法?

    int i = 42;         void *p = &i;         long *lp = &i;
    void *指標可以存放任意物件的地址,i為int型,lp為long int型,型別不匹配。

2.3.3節練習

  • 練習2.25:說明下列變數的值和型別。

    (a) int* ip,i, &r = i;        (b) int i, *ip = 0;     (c) int* ip, ip2;
    
    (a) ip為指標、值不確定,i為int型變數,r為對i的引用,r和i值相同,但i的值不確定     
    (b) i為int型變數、值不確定,ip為指標,ip沒有指向任何物件、故ip值不確定  
    (c) ip為指標,ip2為int型變數,值均不確定

2.4節練習

  • 練習2.26:下面哪些句子是合法的?如果有不合法的句子,請說明為什麼?

    (a) const int buf;             (b) int cnt = 0;
    (c) const int sz = cnt;        (d) ++cnt; ++sz;
    
    (a) 非法,未初始化              
    (b) 合法
    (c) 合法                       
    (d) 非法,++cnt可以,sz的值不可改變,不能++sz

2.4.2節練習

  • 練習2.27:下面的哪些初始化是合法的?請說明原因。

    (a) int i = -1, &r =0;              (b) int *const p2 = &i2;
    (c) const int i = -1, &r =0;        (d) const int *const p3 = &i2;
    (e) const int *p1 = &i2;            (f) const int &const r2;
    (g) const int i2 = i, &r = i;
    
    (a) 非法,引用需要繫結到物件上
    (b) 如果i2為int型則合法,否則非法
    (c) 合法,初始化常量引用允許用任意表示式作為初始值
    (d) 如果i2為int或const int型則合法,否則非法
    (e) 如果i2為int或const int型則合法,否則非法     
    (f) 非法,const r2為對const int的引用,引用必須初始化
    (g) 如果i為int或const int型則合法,否則非法
  • 練習2.28:說明下面的這些定義是什麼意思,挑出其中不合法的。

    (a) int i, *const cp;               (b) int *p1, *const p2;
    (c) const int ic, &r = ic;          (d) const int *const p3;
    (e) const int *p;
    
    (a) cp不合法,const指標本質是一個const物件,const物件必須初始化
    (b) p2不合法,理由同上
    (c) ic不合法,const物件必須初始化   
    (d) p3不合法,定義一個指向int型常量物件的const指標,const指標必須初始化
    (e) 定義一個指向int型常量物件的指標
  • 練習2.29:假設已有上一個練習中定義的那些變數,則下面的哪些語句是合法的?請說明原因。

    (a) i = ic;                         (b) p1 = p3;
    (c) p1 = &ic;                       (d) p3 = &ic;
    (e) p2 = p1;                        (f) ic = *p3;
    
    假定練習2.28中所有定義均合法
    (a) 合法,int變數i可以賦值int型的值
    (b) 非法,p3為const指標,不可改變p3的值
    (c) 非法,不可用普通指標指向const int型物件(但可以用const int型指標指向普通int變數)                
    (d) 非法,p3為指向int型常量的const指標,p3本身的值和指向的物件值均不能變
    (e) 非法,p2為const指標,p2的值不能變              
    (f) 非法,ic為int型常量物件,值不能變

2.4.3節練習

  • 練習2.30:對於下面的這些語句,請說明物件被申明成了頂層const還是底層const?

    const int v2 = 0;        int v1 = v2;
    int *p1 = &v1, &r1 = v1;
    const int *p2 = &v2, *const p3 = &i, &r2 = v2;
    
    v2 頂層const 
    p1非const
    p2是底層const 
    p3左側為底層const、右側為頂層const
    r2為底層const
  • 練習2.31:假設已有上一個練習中所做的那些宣告,則下面的哪些語句是合法的?請說明頂層const和底層const在每個例子中有何體現。

    r1 = v2;
    p1 = p2; p2 = p1;
    p1 = p3; p2 =p3;
    
    r1 = v2; 合法,因為在拷貝時頂層const的影響可以忽略
    p1 = p2; 非法,在拷貝時底層const只能拷貝給底層const,或者非常量轉換為常量。
    p2 = p1;合法,在拷貝時允許非常量轉換為常量。
    p1 = p3; 非法
    p2 = p3;合法

2.4.4節練習

  • 練習2.32:下面的程式碼是否合法?如果非法,請設法將其修改正確。

    int null = 0, *p = null;
    非法 int *p 不能用int型初始化
    改為:constexpr int null = 0, *p = null;
    (constexpr在編譯時將null替換為0,*p = 0合法)
    或 int null = 0, *p = &null;

2.5節練習

2.5.2節練習

  • 練習2.33:利用本節定義的變數,判斷下列語句的執行結果。

    a = 42; b = 42; c = 42;
    d = 42; e = 42; g = 42;
    
    abc正確,deg錯誤
  • 練習2.34:基於上一個練習中的變數和語句編寫一段程式,輸出賦值前後變數的內容,你剛才的推斷正確嗎?如果不對,請反覆研讀本節的示例直到你明白錯在何處為止。

    int i = 0, &r = i;
    auto a = r;
    cout << a <<endl;
    // r是i的別名,i是一個整數,故a為一個整數
    a = 42; //accept
    cout << a << endl;
    
    const int ci = i, &cr = ci;
    auto b = ci; //ci為一個常量,但是auto會忽略const,故b為一個int變數
    cout << b << endl;
    b = 42;
    cout << b << endl;
    
    auto c = cr; //cr是ci的別名,ci為常量,auto忽略const,故b為一個int變數
    cout << c << endl;
    c = 42;
    cout << c << endl;
    
    auto d = &i; //&i為i的地址,故d為一個指向int變數的指標
    cout << d << endl;
    //d = 42; //賦值失敗,d記憶體儲的為一個int變數的地址
    
    auto e = &ci; //&ci為常量ci的地址,故e本來應該為指向常量的指標,但是auto忽略頂層const,故e為一個指向int變數的指標
    cout << e << endl;
    
    auto &g = ci; //ci為一個常量, 故g為一個常量引用
    cout << g << endl;
    // 等式右邊為常量引用,左邊也必須定義為常量形式
  • 練習2.35:判斷下列定義推斷出的型別是什麼,然後編寫程式進行驗證。

    const int i  = 42;
    auto j = i; const auto &k = i; auto *p = &i;
    const auto j2 = i, &k2 = i;
    
    j為int型變數,k為const int &, p為const int *,
    j2為const int,k2為const int &
    
    Code:
    const int i = 42;
    auto j = i;//i為常量,auto判斷會忽略頂層const,故j為int變數
    j = 0; //賦值成功,j為int型
    
    const auto &k = i; // 
    // k = 0; //賦值失敗,因為k為const int&
    
    auto *p = &i;
    // *p = 0; //賦值失敗,*p不可修改,因為p為const int *
    
    const auto j2 = i, &k2 = i; 
    // j2 = 0; //賦值失敗,j2為const int,j2值不可修改
    // k2 = 0; //賦值失敗,k2為const int&, k2值不可修改

2.5.3節練習

  • 練習2.36:關於下面的程式碼,請指出每一個變數的型別以及程式結束時他們各自的值。

    int a =3, b =4;
    decltype(a) c = a;
    decltype((b)) d =a;
    ++c;
    ++d;
    
    a為int型,值為4
    b為int型,值為4
    c為int型,值為4
    d為int &型,值為4
  • 練習2.37:賦值時會產生引用的一類典型表示式,引用的型別就是左值的型別。也就是說,如果i是int,這表示式i=x的型別是int&。根據這一特點,請指出下面的程式碼中的每一個變數的型別和值。

    int a = 3, b = 4;
    decltype(a) c = a;
    decltype(a = b) d =a; //decltype只推斷型別,沒有進行賦值操作
    
    a為int型,值為3
    b為int型,值為4
    c為int型,值為3
    d為int &型,值為3
  • 練習2.38:說明由decltype指定型別和由auto指定型別那個有何區別。請舉出一個例子,decltype指定的型別和auto指定的型別一樣;再舉一個例子,decltype指定的型別與auto指定的型別不一樣。

    auto利用等式右邊的值進行分析,推算所屬型別;
    decltype利用表示式的型別推斷(但不計算表示式的值);
    auto會會忽略引用和頂層const,decltype不會;
    decltype中有三種特殊情況型別推斷會得到引用型別:
        1)表示式的內容是解引用操作
        2)表示式用雙層括號括住
        3)表示式是一個賦值表示式
    
    example:
    int a = 0;
    auto和decltype均得出a為int型
    
    const int b = 0;
    auto推算會忽略頂層const,b型別為int,decltype得到const int;
    

2.6節練習

2.6.1節練習

  • 練習2.39:編譯下面的程式觀察其執行結果,注意,如果忘記寫類定義體後面的分號會發生什麼情況?記錄下相關資訊,以後可能會用。

    srtuct Foo { /* 此處為空 ×/} //注意:沒有分號
    int main()
    {
        return 0;
    }
  • 練習2.40:根據自己的理解寫出Sales_data類,最好與書中的例子區別。

2.6.2節練習

  • 練習2.41:使用你自己的Sales_item類重寫1.5.1節、1.5.2節和1.6節的練習。眼下先把Sales_data類的定義和main函式放在同一個檔案裡。

2.6.3節練習

  • 練習2.42:根據你自己的理解重寫一個Sales_data.h標頭檔案,並以此為基礎重做2.6.2節練習。

    • 練習1.3:編寫程式,在標準輸出上列印Hello,World。
    int main()
    {
        std::cout << "Hello, world!" << endl;
        return 0;
    }

相關文章