C++ concepts

第一章

  • 变量,具有名字的对象
  • 缓冲区,一个存储区域,用于保存数据。IO设施通常将输入输出数据保存在一个缓冲区中。
  • 文件结束符(end of file, EOF),文件结束标志,通常是-1。
  • 初始化,对象创建的时候给它一个初始值。
  • 未初始化的变量,没有给定初始值的变量,类类型的变量如果没有指定初值,按类定义指定的方式进行初始化。函数内部的内置类型变量默认是不初始化的,需要进行显式的初始化。

第二章

  • 无法预知的行为,编译器无须或者不能检测的错误。即使代码编译通过了,如果程序执行了一条未定义的表达式,仍有可能产生错误,而且这是很有可能的。

  • 字面值常量:12, 024, 0x3,true, 3.141, nullptr,A都是字面值常量,他们分别属于int,int,int, bool, double, 指针,char等类型。可以通过前缀或者后缀显式的指定字面值的类型,字符和字符串的字面值类型通过前缀指定,整形和浮点型的字面值类型通过后缀指定。

  • 字面值类型:算术类型,引用和指针都属于字面值类型,string,IO库和类不属于字面值类型。算术类型包含整形和浮点型,整形中又包含字符和int,long等。constexpr只能用于字面值类型。

  • 在将有符号数转化为无符号数的时候,如果这个有符号数是负数,那么会做一个模运算,将它转换为正值。

  • 有符号数永远不可能为负。

  • 不要混用无符号类型和有符号类型,因为有符号数会被转化成有符号数进行运算。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int a = -3;
    unsigned int b = 0;

    b --;
    std::cout << b << std::endl;

    b = a;
    std::cout << b << std::endl;

    b = 3;
    std::cout << a* b << std::endl;

  • 不要用char进行算术运算,因为不同的平台实现可能不同,有的是无符号的,有的是有符号的。

  • 常见的未定义行为:

  1. 1
    2
    int i = 1;
    i = i++;
  2. 给带符号数一个超出它表示范围的值。

  • 默认初始化,变量没有指定初值,被赋予默认值。默认值由变量类型和变量位置决定。
    对于内置类型的变量,如果没有显式初始化,它的位置由定义的位置决定。函数内部的内置类型不会被初始化,定义于任何函数外部的内置类型被初始化为$0$。未初始化的变量的值是未定义的。
    对于自定义的类型来说,每个类决定初始化对象的方式,而且是否允许不经过初始化就定义对象也由自己决定。如果类允许这种行为,由类决定对象的初始值是什么;如果类要求每个对象显示初始化,在创建类对象没有进行明确的初始化操作时,会引发错误。

  • 未初始化变量。

  • 声明和定义的区别和联系。

  • 在函数体内部不能初始化由extern关键字标记的变量。

  • 静态类型,在编译阶段检查类型。

  • 类型修饰符:*&,它是声明符的一部分,const也是类型修饰符。

  • 声明符:变量名或者变量名前面加上类型修饰符,即*d&d,其中d是变量名。

  • 复合类型:基于其他类型定义的类型,引用和指针都是复合类型。

  • 引用就是别名,不能更改,必须初始化。

  • 指针存放的是某个对象的地址,要想获取变量的地址,使用&符号获取变量的地址。

  • 建议初始化所有指针。如果指针未经初始化,该指针变量中存放的值被当做一个地址,访问该指针,相当于访问一个本不存在的变量,如果这个地址中的内容被我们拿到了,我们可能就不知道这个值是合法还是非法的。建议初始化所有的指针,不知道指针应该指向什么的话,就让指针指向nullptr或者0

  • 复杂的指针或者引用的声明语句,从右往左读。

  • 常量引用是对const的引用的简称。严格来说,并不存在常量引用,因为引用不是一个对象,我们没办法让引用本身恒定不变。但是因为C++中,引用绑定的对象是不能更改的,所以从这层意义上理解,所有的引用又都称得上常量。引用的对象是常量还是非常量决定了引用能进行的操作,但是影响不到引用和对象的绑定关系。

  • 指向常量的指针和对常量的引用(常量引用),可以使用非常量对象初始化指向常量的指针和常量引用,不论指向或者引用的是不是常量对象,都不能通过指针或者引用修改他们引用或者指向的对象的值。因为他们认为自己指向或者引用了常量,而常量是不能修改的,所以就不能修改了。

  • 常量指针即指针本身是一个常量。它的指向不能改变,但是它指向变量的值是可以改变的。

    1
    2
    3
    4
    int val =3;
    const int &cr = val; // 对常量的引用,引用的变量不能通过cr引用改变。
    cont int *ptr = &val; // 指向常量的指针,指针指向的变量不能通过ptr指针改变。
    int *const p = &val; //常量指针,指针的指向不能变,指针指向变量的值可以改变。

  • 顶层const,变量本身是一个常量。

  • 底层cosnt,针对于复合类型如指针和引用来说的,引用的对象是一个常量(常量引用)或者指针指向的是一个常量。

  • 顶层const和底层const
    对常量的引用(常量引用)可以和常量对量绑定;
    对常量的引用(常量引用)可以和非常量对量绑定;
    非常量引用不可以和常量对象绑定;
    非常量引用可以和非常量对象绑定;
    指向常量的指针可以指向常量对象;
    指向常量的指针可以指向非常量对象;
    常量指针可以指向非常量对象;
    常量指针不可以指向常量对象;
    普通指针不可以指向常量对象;
    普通指针可以指向非常量对象;
    常量指针(顶层const)可以用来初始化非常量对象。
    对常量的引用和指向常量的指针(底层const)不可以用来初始化非常量对象。

  • 常量表达式,值不会改变并且在编译时值就已经确定的表达式。

  • constexpr`用于声明常量表达式,常量表达式一定是常量,但是常量不一定是常量表达式。比如:

    1
    const int sz = get_size() //sz是常量,但是不是常量表达式

  • auto会忽略顶层const,保留底层const

  • auto也会忽略引用。

  • 设置类型为auto的引用,可以保留顶层const

  • decltype的结果可以是引用,引用从来都是作为它所指对象的同义词出现,只有在decltype处是例外。

  • 如果表达式的内容是解引用操作,使用decltype将会得到引用类型。

  • decltype((variable))的结果永远是引用,而decltype(variable)的结果只有在真的是引用的时候才会返回引用。

第三章

  1. cingetline的区别,对于空白符的处理
  2. string的初始化方式,默认初始化,拷贝初始化,直接初始化
  3. range for语句逐字符操作。

第七章

  • 构造函数。每个类都会定义它的对象被初始化的方式,类通过一个或者几个特殊的成员函数控制每个类的初始化过程,这些函数叫做构造函数。
  • 前向声明。仅仅声明类而暂时不定义它,这种声明有时候也叫前向声明。
  • 不完全类型。在类声明之后定义之前,这个类属于不完全类型。我们知道它是一个类,但是不清楚它到底包含哪些类型。

参考文献

1.《C++ Prime第五版》