C++ Primer 第二章 学习笔记及习题答案

本文深入解析C++中的基本内置类型,包括算数类型、空类型、带符号和无符号类型的选择策略,以及类型转换规则。同时,详细介绍了整型、浮点型和字符字符串字面值的表示形式,变量的定义、初始化与作用域,引用、指针与const的概念和使用技巧,提供了丰富的实例和练习题,帮助读者掌握C++的基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

知识点

基本内置类型

  • 算数类型:整型(包括布尔型和字符型)、浮点型、空类型。
  • 空类型:不对应任何值,常用来当函数不返回任何值时使用空类型作为返回类型。
  • 带符号类型和无符号类型:带符号类型可以表示正数、负数、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"
      • 注意:字符串字面值实际上是由常量字符构成的数组,在每个字符串结尾处添加空字符'\0',字符串字面值的实际长度比它的内容多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 F\145rgus?\012"
    (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 <<"2\115\n" << std::endl;
        std::cout << "2\t\115\n" << 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初始值为"\0",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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值