《C++ Primer》笔记(第01-04章)

第1章 快速入门

  1. Windows下查看程序返回值:echo %ERRORLEVEL%
  2. endl是一个特殊值,称为操纵符(manipulator),将其写入输出流时将会输出换行效果并刷新与设备相关联的缓冲区
  3. "A"表示包含字母A和空字符两个字符的字符串
  4. 宽字符:wchat_t ch=L'a';
  5. 宽字符串:L"hello"(包含了最后的宽空字符)

第2章 变量和基本类型

  1. 变量名不能包含两个连续的下划线,也不能以下划线开头后面紧跟一个大写字母
  2. 定义和声明的区别:
    • 定义:为变量分配存储空间,还可以为变量指定初值
    • 声明:用于向程序表明变量的类型和名字
  3. 定义也是声明:当定义变量时我们声明了它的类型和名字
  4. 如果声明有初始化式,那么它可被当作是定义,即使被标记为extern。如:

    extern int x = 10;

  5. 只有当extern声明位于函数外部时,才可以含有初始化式(此时被当成定义)
  6. 与一般的变量不同,在全局作用域声明的const变量是定义该对象的文件的局部变量。此变量只存在于那个文件中,不能被其他文件访问。除非定义时加上extern
  7. 引用是一种复合类型(是指用其他类型定义的类型)
  8. const引用可以初始化为不同类型的对象或者初始化为右值,如字面值常量:

    int i = 42;
    const int &r = 42;
    const int &r2 = r + i;
    const int &r3 = i;
    

    但同样的初始化对于非const引用都是不合法的,因为对于:

    double dval = 3.14;
    const int &ri = dval;
    

    编译器会将其变成:

    int temp = dval;
    const int &ri = temp;
    

    如果ri不是const,则可对其赋值,但不会修改dval,矛盾。

  9. const的引用只能绑定到与该引用同类型的对象;const引用则可以绑定到不同但类型相关的对象或右值。
  10. 枚举成员的值可以不唯一,如:enum { a = 2, b, c = 3, d };其中bc都是3。
  11. 不能把int等类型赋值给枚举类型的对象
  12. 用于初始化的值必需是一个常量表达式,即在编译时就可以计算出值的表达式
  13. 头文件一般包含:类的定义、extern变量的声明和函数的声明
  14. 对于“头文件不应含有定义”这一规则,有三个例外:头文件可以定义类、值在编译时就已知的const对象和inline函数。这些实体可在多个源文件中定义,只要在每个源文件中的定义是相同的。p68
  15. 当在头文件中定义了const变量后,每个包含该头文件的源文件都有了自己的const变量,其名称和值都一样;定义在头文件中的const变量应该是常量表达式。
  16. const变量不是用常量表达式初始化,就不应在头文件中定义,而应在源文件中定义并初始化,并添加extern使其被多个文件共享。
  17. 若在头文件中定义externconst变量,多个cc文件都#include了这个头文件且其obj会被链接到一起时,会出错:重定义。原因:这些cc文件引用头文件后相当于在文件中定义了这个const变量,但由于加了extern,使其全局可见。
  18. 可以声明引用,例如在a.cc中定义:

    const int a = 100;
    const int &ra = a;
    

    则可以在a.h中声明:extern const int &ra;

  19. 逗号表达式与定义,以下是合法的:

    const int i = 0, *p = i;
    const int j = 0, *q = &i;
    

第3章 标准库类型

  1. getline(cin, line)getline遇到第一个换行符就中止,即使cin的第一个字符就是
  2. string的“+”操作符左右两边必须至少有一个是string类型
  3. string对象的下标变量应为string::size_type
  4. 注意区分const_iteratorconstiterator
  5. 任何改变vector长度的操作都会使已存在的迭代器失效。

第4章 数组和指针

  1. 数组元素的类型不能是引用
  2. 如果没有显式提供元素初值,数组元素会像普通变量一样初始化(2.3.4节):
    • 在函数体外定义的内置数组,元素均初始化为0
    • 在函数体内定义的内置数组,元素无初始化
    • 不管数组在哪定义,若其元素为类类型,则用default constructor来初始化;若该类没有default constructor,则必须显式初始化。
  3. 字符数组:字符串的字面值包含一个额外的null字符

    char ca1[] = { 'c', '+', '+' };  //长度为3
    char ca2[] = "c++";  //长度为4
    char ca3[3] = "c++";  //编译错误
    
  4. 对指针进行初始化和赋值只能使用:
    • 0值常量表达式
    • 类型匹配的对象地址
    • 另一对象之后的下一地址
    • 同类型的另一个有效指针
  5. void*指针可以保存任何类型对象的地址,不允许使用void*指针操纵它指向的对象
  6. 两个指针减法操作的结果是标准库类型ptrdiff_t的数据。
  7. 与任何const量一样,const指针也必须在定义时初始化。
  8. 考虑如下代码:

    typedef string *pstring;
    const pstring cstr;
    

    这里const修饰的是pstring类型,这是一个指针。因此上述定义等价于

    string * const cstr;
    
  9. 可以在数组长度后加()来对数组元素做值初始化:

    int *p = new int[10]();  // 初始化为0
    

    若不加()对于内置类型是不初始化的,也不能用初始化列表。

  10. const对象的动态数组对于内置类型一定要加()
  11. c++允许动态分配空数组
lambda /
Published under (CC) BY-NC-SA in categories 程序&设计  tagged with c++  读书笔记