C++ Primer Plus学习笔记

发布时间 2023-07-29 12:24:44作者: kaling
  • 仅限main函数,如果没有返回语句,编译器会加隐含的返回语句:return 0;
  • WIN10 64位系统中,sizeof(int) == sizeof(long) == 4.
  • C++ 17之后,新增byte数据类型,在标头<cstddef>中定义,取值范围[0-255],初始化:std::byte b{42};
  • char取值范围[-128 ,127]
  • 原始字符串 R"(string)" R"+*(string)+*",如实输出string.
  • cout使用数字转义序列输出字符时,只能基于字符的八进制和十六进制编码.美元符号ASCII码,$:044 0x24,可以使用下列代码输出:cout << "\044";或者 cout << "\x24";十六进制转义字符只能使用x,不能是大写,也不能是"\0x24".
  • cin cout将输入和输出看做char流,wcin wcout可以处理wchar_t流.
  • wchar_t bob = L'P'; wcout << L"tall";
  • 强制类型转换:C风格 (typeName)value; C++风格typeName(value);
  • 将值从一种数值类型转为另一种数值类型:static_cast<typeName>(value);
  • 只有在定义数组时才能使用初始化,也不能将一个数组赋给另一个数组.可以使用下标分别给数组中的元素赋值.
  • 一定要在对指针应用取值运算符*之前,将指针初始化为一个确定适当的地址.
  • int * pn = new int; typeName * pointer_name = new typeName;
  • new与delete要配对使用.删除指针,代表释放指针指向的内存,但指针变量不会被删除,可以让指针变量指向另一块新分配的内存.
  • int arr[3] = {1,2,3};int* pt = arr; sizeof(arr)==12 sizeof(pt)==4
  • 数组名arr == &arr[0] &arr得到的是整个数组的地址,2个值数字上相等.
  • int (*pa)[3] = &arr;pa是指向包含3个整数的数组的指针,类型为int(*)[3]
  • *pa与arr等价,(*pa)[0]为arr数组的第一个元素.
  • 数组名有时候代表指向数组第一个元素的指针,有时候代表整个数组.
  • int age = 39;age是变量.const int* pt = &age; const表示不能通过指针修改age值,但是可以让pt指向另一个变量.
  • 非const指针只能指向非const数据的地址,const指针可以指向const或非const数据.引用与此类似.
  • 在多数C++表达式中,char数组名、char指针以及用引号括起来的字符串常量都被解释成字符串第一个字符的地址.
  • char t[3] = "ab";cout<<t;表示输出字符串ab.cout<<(int*)t;输出地址.
  • 包含字符,但不以空值字符结尾的char数组只是数组,不是字符串.
  • 任何值或任何有效的值和运算符的组合都是表达式.C++中每个表达式都有值.
  • 表达式加分号成为语句,但语句去掉分号并不一定是表达式.有些语句没有值.
  • 别名:typedef typeName aliasName;
  • decltype(x) y;让y类型与x相同.
  • cin.get()读取一个字符并返回int类型字符编码;cin.get(ch),读取一个字符存入ch变量,此处ch为引用参数.char name[size]; cin.get(name, size);表示连续读取字符,直到遇到'\0'或读取字符数目达到size-1.
  • cin.good();查看cin状态,如果为0,用cin.clear()重置状态,才能继续读取.
  • cin>>抽取运算符查看输入流时,跳过空白,它读取从非空白字符开始,直到下一个空白,或与目标类型不匹配的第一个字符之间的全部内容.
  • cin或cout对象包含一个描述流状态的数据成员,流状态由三个ios_base元素组成:eofbit badbit failbit,取值为1(设置)或0(清除).三状态全为0表示顺利,good()返回true.clear()清除状态,三元素都设置0,此时,bool(cin)=true
  • C++一些运算符有字符替代标记. &&:and &:bitand |:bitor ~:compl !:not
  • !=:not_eq ||:or ^:xor 
  • 不加括号的函数名代表函数的地址,函数指针.加括号函数名代表函数返回值.
  • 要声明指向特定类型函数的指针,可以先编写这种函数的原型,然后用(*pf)替换函数名,这样pf就是这类函数的指针.
  • int (*pf)(int);pf是函数指针.int *pf(int);pf是返回int*指针的函数.
  • 内联函数在编译时,编译器直接使用内联函数代码替换函数调用,程序无需跳到另一个位置执行代码,执行完毕再跳回来.内联函数不能递归.函数定义前加inline就变成内联函数.
  • 引用变量是变量的别名,主要用途是作函数的形参.通过将引用变量用作参数,函数将使用原始数据,而不是其副本.
  • 左值标识一个可以修改的内存块,右值是不能通过地址访问的值.常规函数返回的是右值,返回值位于临时内存单元中,运行到下一条语句时可能已不存在.
  • 右值是不能对其应用地址运算符的值,包括字面常量,诸如x+y等表达式以及返回值的函数.右值引用关联到右值,使该右值被存储到特定的位置,且可以获取该位置的地址.通过将右值数据与特定的地址关联,使得可以通过右值引用来访问该数据.
  • 对于给定的函数名,可以有非模板函数、模板函数和具体化模板函数以及他们的重载版本.具体化模板函数优先于模板函数,非模板函数最优先使用.
  • 模板函数以template <typename T>开头,具体化模板函数以template<>开头.
  • 函数内部定义的类称为函数符.编译器显式创建特定类型的模板,称为实例化.在同一个文件中不能同时使用同一种类型的显式实例化和显式具体化.
  • decltype(expression) var; var与expression类型相同.
  • 函数原型的参数列表中,变量名相当于占位符,可有可无,也不必与定义中的变量名相同.
  • lambad函数可访问作用域内任何动态变量,要捕获要使用的变量,可以将其放入中括号内.[x](){}表示按值访问变量x;[&x]表示按引用访问变量x;[&]按引用访问所有动态变量;[=]按值访问所有动态变量;[x,&y]按值访问x,按引用访问y;[&,x]按值访问x,按引用访问其他所有动态变量.
  • 类描述了一种数据类型的全部属性,对象是根据这些描述创建的实体.
  • 函数外部声明的静态变量,如果有static限定符,则作用域为当前整个文件;如果没有static限定符,则为全局变量,外部文件也可访问;代码块内声明的static变量,没有链接性,只能块内访问.
  • 所有静态变量,如果没有明确初始化,则变量所有位都被设置为0.
  • 多文件程序中,可以在一个文件中定义一个全局变量,使用该变量的其他文件必须使用关键字extern声明它.
  • 任何一个变量只能定义一次,定义给变量分配存储空间,
  • const全局变量是内部的,就像用了static限定符一样,除非加了extern限定符.
  • 定义于类声明中的函数自动成为内联函数.类声明之外的函数想成为内联函数,必须在实现部分使用inline限定符.
  • 构造函数的参数表示的不是类成员,而是赋给类成员的值,因此参数名不能与类成员相同,否则最终代码会是这样:shares = shares;
  • 当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数.为类定义构造函数后,程序员应为类提供默认构造函数.隐式调用默认构造函数时,不需要使用圆括号.Stock third;
  • 列表初始化可以用于类,只要提供与某个构造函数的参数列表匹配的内容,并用大括号将它们括起.Stock third = {"no name",0,0.0};
  • 类中函数声明和定义括号后面加const,保证函数不会修改调用对象.这种类函数被称为const成员函数.
  • 初始化新对象原型:Stock(string& s);1.Stock a = Stock("abc");2.Stock a("abc");3.Stock *ps = new Stock("abc");4.Stock a = {"abc"};5.Stock a {"abc"};6. Stock *pa = new Stock{"abc"};7.Stock a = new Stock;[调用默认构造函数]
  • 类作用域:要调用类public函数,必须通过对象;定义成员函数时,必须使用作用域解析运算符.
  • 类内定义常量时,使用关键字static. static const int Months = 12;
  • 类内定义枚举,添加struct或class关键字.enmu struct egg{Small,Medium}.
  • 常规枚举可以自动转换成整型,类作用域内枚举只能显式转换成int.
  • 通常public方法是访问private成员的唯一途径,友元可以突破这种限制.友元有三种:友元函数、友元类和友元成员函数.
  • 类的友元函数是非成员函数,其访问权限与成员函数相同.
  • 只接受一个参数的构造函数定义了从参数类型到类类型的转换.
  • 除非是const整型或枚举型,不能在类声明中初始化静态成员变量,因为声明描述了如何分配内存,但并不实际分配内存.
  • 静态数据成员在类声明中使用static关键字声明,在包含类方法的文件中初始化.初始化时使用作用域运算符来指出静态成员所属的类,不要添加static关键字.
  • 如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这被称为深度复制.可以防止调用析构函数时释放已经被释放的数据.
  • 类构造函数成员初始化列表由逗号分隔的初始化列表组成,前面带冒号.位于参数列表的右括号之后,函数体左括号之前.如果数据成员名称mdata,需要初始化为val,则初始化器为mdata(val).初始化工作进行时,构造函数大括号中的代码还没运行.
  • 当初始化列表包含多个项目时,这些项目被初始化的顺序为它们被声明的顺序,而不是它们在初始化列表中的顺序.
  • 创建派生类对象时,程序首先调用基类构造函数,然后再调用派生类构造函数.派生类构造函数首先接受实参并赋值参数列表中的形参,之后将这些参数作为实参传递给基类构造函数.基类构造函数负责初始化继承的数据成员;派生类构造函数主要有用于初始化新增的数据成员.派生类构造函数总是调用一个基类构造函数.派生类对象过期时,程序将首先调用派生类析构函数,然后再调用基类析构函数.
  • 基类指针可以在不进行显示类型转换的情况下指向派生类对象;基类引用可以在不进行显示类型转换的情况下引用派生类对象.基类指针或引用只能用于调用基类方法.
  • C++有三种继承方式:公有继承保护继承和私有继承.公有继承建立一种is-a关系,即派生类对象也是一个基类对象,可以对基类对象执行的任何操作也可以对派生类对象执行.
  • 类的私有成员只能在类内部访问,即便是类生成的对象也无法访问.
  • 父类与子类都有一个同样签名的函数,父类指针指向子类对象,通过这个指针调用同名函数时,如果函数有virtual关键字,指针调用的是子类函数,如果没有virtual关键字,指针调用的是父类函数.
  • 父类中的虚函数,子类中自动成为虚函数.virtual只用于类声明的方法原型中,函数定义时没有virtual关键字.
  • 子类重新定义一个与父类参数不同的同名函数会把父类同名函数隐藏,不会生成重载版本.
  • C++抽象类,函数声明的结尾处使用=0.抽象类不能创建类的对象,只能作为基类.
  • 静态成员会被继承,但不会给它新开空间.父类子类共用同一个静态成员.
  • 当基类和派生类都采用动态内存分配时,派生类的析构函数、复制构造函数、赋值运算符都必须使用相应的基类方法类来处理基类元素.这种要求是通过三种不同的方式来满足的.对于析构函数,这是自动完成的;对于构造函数,这是通过在初始化成员列表中调用基类的复制构造函数来完成的,如果不这样做,将自动调用基类的默认构造函数;对于赋值运算符,这是通过使用作用域解析运算符显示地调用基类的赋值运算符来完成的.
  • 使用包含时将使用对象名来调用方法,使用私有继承时将使用类名和作用域解析运算符调用方法.