C++ Primer 第五版

  • 当我们使用istream对象作为条件时,其效果是检测流的状态.
  • char:[-128,127].
  • C++ 17新增byte数据类型,在<cstddef>头文件中定义,取值范围:[0,255].
  • int和long都占用4字节空间.
  • 切勿混用带符号类型和无符号类型.
  • \后跟3位以内8进制数字,或\x后跟一个或多个16进制数字都可以代表字符.
  • 原始字符串:[R"(string)"] 或 [R"+*(string)+*"]
  • 初始化不是赋值,初始化是创建变量时赋予其一个初始值,赋值是把对象的当前值擦除,而以一个新值来替代.
  • 任何值,或值与运算符组合都是表达式,每个表达式都有一个值.表达式加分号称为语句,但语句去掉分号不一定是表达式,有些语句没有值.
  • 为了支持分离式编译,C++将声明和定义区分开来.声明规定了变量类型和名字,定义申请存储空间.变量能且只能被定义一次,但是可以被多次声明.
  • nullptr,0,NULL<cstdlib>都可以代表空指针.void*可以指向任意类型的变量,也可以是空指针.void*仅指向某个内存空间,无法访问内存空间中的变量.
  • 要在多个文件之间共享const变量,须在变量声明定义之前都添加extern关键字.
  • 常量引用可以指向常量对象,也可以指向非常量对象.非常量引用不能指向常量对象,只能指向非常量对象.指针也一样.
  • 常量表达式是指不会改变,并且在编译期间就能得到结算结果的表达式.
  • [&&:and] [!:not] [!=:not_eq] [||:or]
  • int arr[3]={1,2,3}; int* pt=arr; arr有双重含义:数组名和指向首元素的指针.sizeof(arr)代表数组占用空间12字节;sizeof(pt)代表指针变量占用空间,X86平台4字节,X64平台8字节.arr等同于&arr[0],与&arr数值相等,但一个代表首元素地址,一个代表数组地址.arr+1地址加4;&arr+1地址加12.
  • int (*parr)[3]= &arr:parr是指向含有三个整数元素数组的指针,类型为int(*)[3].*parr与数组名arr等价,与首元素指针arr不等价.(*parr)[0]代表数组首元素.
  • 容器使用size_type类型表示大小,数组用site_t类型表示大小.
  • int * pn = new int; typeName * pointer_name = new typeName;
  • new与delete要配对使用.删除指针,代表释放指针指向的内存,但指针变量不会被删除,可以让指针变量指向另一块新分配的内存.
  • char t[3] = "ab";cout<<t;表示输出字符串"ab";cout<<(int*)t;输出地址.
  • 别名:typedef typeName aliasName;
  • cin.get()读取一个字符并返回int类型字符编码;cin.get(ch),读取一个字符存入ch变量,此处ch为引用参数.char name[size]; cin.get(name, size);表示连续读取字符,直到遇到'\0'或读取字符数目达到size-1.
  • %只适用于整数类型,int long short char等.m == (m/n) * n + m % n
  • 左值标识一个可以修改的内存块,右值是不能通过地址访问的值.常规函数返回的是右值,返回值位于临时内存单元中,运行到下一条语句时可能已不存在.
  • 右值是不能对其应用地址运算符的值,包括字面常量,诸如x+y等表达式以及返回值的函数.右值引用关联到右值,使该右值被存储到特定的位置,且可以获取该位置的地址.通过将右值数据与特定的地址关联,使得可以通过右值引用来访问该数据.
  • 引用变量是变量的别名,主要用途是作函数的形参.通过将引用变量用作参数,函数将使用原始数据,而不是其副本.
  • decltype(expression) var; var与expression类型相同.
  • 函数形参的作用域就是函数体.
  • 函数参数列表的实质是形参的声明,函数执行的第一步是隐式地定义形参,并用实参初始化形参.通常是把实参的拷贝赋值形参,如果形参是引用类型,则直接使用实参本体.
  • 函数原型的参数列表,变量名相当于占位符,可有可无,也不必与函数定义中的形参名相同.
  • 函数体内定义的static变量,作用域是函数体,生命周期与程序相同.可以用局部静态变量来统计函数执行的次数.
  • 函数外部声明的变量,如果有static限定符,作用域为当前整个文件;如果没有static限定符,则为全局变量,外部文件也可访问;代码块内声明的static变量,没有链接性,只能块内访问.所有静态变量,如果没有明确初始化,则变量所有位都被设置为0.
  • 应当把函数名当做指向函数的const指针看待.
  • int next(int n){return n+1;} int (*const fp)(int)=next; ::next==fp True.
  • const全局变量是内部的,就像用了static限定符一样,除非加了extern限定符.
  • 指针const:顶层const表示指针本身是常量,底层const表示指针指向的对象是常量.顶层const对对象拷贝操作没有影响.底层const指针或引用可以绑定或指向非const对象,反之则不行.
  • 数组做函数形参时,数组会被转换成指向首元素的指针,调用者负责管理指针,防止越界.
  • 内联函数在编译时,编译器直接使用内联函数代码替换函数调用,程序无需跳到另一个位置执行代码,执行完毕再跳回来.内联函数不能递归.函数定义前加inline就变成内联函数.定义在类内部的函数是隐式inline函数.
  • 函数返回值的方式和初始化一个变量的方式完全一样:返回的值用于初始化调用点的一个临时变量,该临时变量就是函数调用的结果.返回局部变量意味着把局部变量的值拷贝到调用点临时变量中.函数运行完毕,局部变量会自动消失.不要返回局部变量的指针或引用.
  • int add(int,int);当把函数名add作为一个值使用时,函数名自动转换成指针,int(*f)(int,int)=add,add等同于&add.函数返回函数指针时,不能直接使用函数名代表函数指针.
  • 构造函数的参数表示的不是类成员,而是赋给类成员的值,因此参数名不能与类成员相同,否则最终代码会是这样:shares = shares;
  • 列表初始化可以用于类,只要提供与某个构造函数的参数列表匹配的内容,并用大括号将它们括起.Stock third = {"no name",0,0.0};
  • 类中函数声明和定义括号后面加const,保证函数不会修改调用对象.这种类函数被称为const成员函数.
  • 类的私有成员只能在类内部访问,即便是类生成的对象也无法访问.
  • 友元函数不是类的成员函数,不能用点运算符调用.友元函数不加friend就是一个普通函数,无法访问类的私有变量,加了friend就变成了能访问类私有变量的普通函数.
  • 类构造函数成员初始化列表由逗号分隔的初始化列表组成,前面带冒号.位于参数列表的右括号之后,函数体左括号之前.如果数据成员名称mdata,需要初始化为val,则初始化器为mdata(val).初始化工作进行时,构造函数大括号中的代码还没运行.当初始化列表包含多个项目时,这些项目被初始化的顺序为它们被声明的顺序,而不是它们在初始化列表中的顺序.
  • 只接受一个参数的构造函数定义了从参数类型到类类型的转换.
  • 一个类就是一个作用域,在类的外部定义成员函数时,必须同时提供类名和函数名.因为在类的外部,成员的名字被隐藏.
  • 类的静态成员与类关联,不与任何类对象绑定.对象中不包含任何与静态成员有关的数据.可以通过类,也可以通过对象或其指针访问静态成员.static只出现在声明语句中.
  • cout << ...; flush ends endl,都可以刷新缓冲区.endl换行,ends输出空字符,flush只刷新缓冲区.cout << unitbuf表示所有输出操作立刻刷新缓冲区.
  • auto old = cin.rdstate(); cin.clear(); ... cin.setstate(old);保存清除恢复流状态操作.
  • 容器的begin()函数返回的迭代器指向容器首元素,end()函数返回的迭代器指向超尾元素.容器元素的范围[begin, end).如果begin与end相等,则容器为空.
  • lambda函数只有[]中捕获它所在函数的局部变量,才能在函数体中使用该变量.[capture list](parameter list) -> return type { function body },[=]代表值隐式捕获,[&]代表引用隐式捕获.
  • set:有序不重复集合;map:关键字不重复的有序键值对,又称关联数组.
  • 每个shared_ptr都有一个关联的计数器,一旦计数器变为0,它会自动释放对象.
  • shared_ptr<int> p(new int(1024));共享指针只能使用直接初始化形式,不能采用shared_ptr<int> p = new int(1024);
  • shared_ptr<int> p = make_shared<int>(42);
  • shared_ptr<string> p = make_shared<string>(10, '9');
  • 在一个类模板的作用域内,可以直接使用模板名而不必指定模板实参.
  • 模板函数以template <typename T>开头,具体化模板函数以template<>开头.
  • 模板类,在类的范围里,可以无需加类型限定词就直接使用;在类的范围以外,必须使用类型参数来限定.
  • 类内定义常量时,使用关键字static. static const int Months = 12;
  • 常规枚举可以自动转换成整型,类作用域内枚举只能显式转换成int.
  • 静态数据成员在类声明中使用static关键字声明,在包含类方法的文件中初始化.初始化时使用作用域运算符来指出静态成员所属的类,不要添加static关键字.
  • 如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这被称为深度复制.可以防止调用析构函数时释放已经被释放的数据.
  • 创建派生类对象时,程序首先调用基类构造函数,然后再调用派生类构造函数.派生类构造函数首先接受实参并赋值参数列表中的形参,之后将这些参数作为实参传递给基类构造函数.基类构造函数负责初始化继承的数据成员;派生类构造函数主要有用于初始化新增的数据成员.派生类构造函数总是调用一个基类构造函数.派生类对象过期时,程序将首先调用派生类析构函数,然后再调用基类析构函数.
  • 基类指针可以在不进行显示类型转换的情况下指向派生类对象;基类引用可以在不进行显示类型转换的情况下引用派生类对象.基类指针或引用只能用于调用基类方法.
  • C++有三种继承方式:公有继承保护继承和私有继承.公有继承建立一种is-a关系,即派生类对象也是一个基类对象,可以对基类对象执行的任何操作也可以对派生类对象执行.
  • 父类与子类都有一个同样签名的函数,父类指针指向子类对象,通过这个指针调用同名函数时,如果函数有virtual关键字,指针调用的是子类函数,如果没有virtual关键字,指针调用的是父类函数.
  • 父类中的虚函数,子类中自动成为虚函数.virtual只用于类声明的方法原型中,函数定义时没有virtual关键字.
  • 子类重新定义一个与父类参数不同的同名函数会把父类同名函数隐藏,不会生成重载版本.
  • C++抽象类,函数声明的结尾处使用=0.抽象类不能创建类的对象,只能作为基类.
  • 静态成员会被继承,但不会给它新开空间.父类子类共用同一个静态成员.
  • 当基类和派生类都采用动态内存分配时,派生类的析构函数、复制构造函数、赋值运算符都必须使用相应的基类方法类来处理基类元素.这种要求是通过三种不同的方式来满足的.对于析构函数,这是自动完成的;对于构造函数,这是通过在初始化成员列表中调用基类的复制构造函数来完成的,如果不这样做,将自动调用基类的默认构造函数;对于赋值运算符,这是通过使用作用域解析运算符显示地调用基类的赋值运算符来完成的.

  • 派生类中不需要重定义虚函数,它可以继承其最近的基类中该虚函数的定义,但是该类中第一次被声明的虚函数必须在该类中进行定义.
  • 如果我们想用一个指向基类的指针来删除一个实际上可能是派生类的对象,基类中需要声明一个虚析构函数.如果析构函数只完成默认操作,派生类中不需要重定义析构函数,会自动继承基类的析构函数.
posted @ 2023-08-01 09:36  kaling  阅读(71)  评论(0编辑  收藏  举报