注:本次复习只关注于一些我所认为对自己有价值的东西,特别基础的东西不会写在本篇文章中
- 第一章 预备知识
- OOP(object oriented programming)面向对象编程
- 编译器:源代码->目标代码->连接程序->可执行代码
- 第二章 开始学习c++
- main()会被启动代码调用,启动代码是编译器添加到程序中的,通常从main()处开始执行
- 预处理器:在主编译之前对源文件进行处理:如include
- 不同形式的头文件对名称空间即using namespace的要求有差别
- 变量的声明:避免拼写错误
- 第三章 处理数据
- 如果想用不同的字符集,可以在前面加上\U或\u
- wcha_t:宽字符类型,可以表示扩展字符集
- char16_t,char32_t
- 第四章 复合类型
- 数组初始化:int card[4]={1,2,3,4};int card[4]={0}(全赋值为0)
- cin会遇到空白(空格,制表符,换行符)确定字符串的结束位置
- cin.getline(name,num):面向行的输入(针对char[])
- cin.get(name,num)和cin.get()(针对char[])
- 混合输入数字和面向行的字符串会导致问题
- getline(cin,str)
- 共用体union 节约空间
- 枚举enum
- 一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的,适当的地址,这是关于使用指针的金科玉律
- 数组名和数组名的地址在数值上相同,一个是首元素的地址,一个是整个数组的地址,但在指针运算上有差异
- 第五章 循环和关系表达式
- for(i=0,j=10;i<j;i++,j–)
- int * a,b :b是int
- define和typedef都是处理别名替换,但typedef能处理更复杂的类型别名
- 第六章 分支语句和逻辑运算符
- cctype库中的字符函数
- 第七章 函数
- 函数原型:描述了函数到编译器的接口
- 数组做参数(int arr[])或(int * arr)
- int age = 39 ; const int * pt = &age;在这里面const限定了pt指向的int不能通过*pt改变,并不是说指向的真正是一个常量,而是相对于pt是一个常量,还是可以通过直接修改age来使age的值发生变化
- 可以将const变量的地址赋给const指针,但不能赋给非const指针
- int * const pt:指针本身是常量
- int *pt[4] int pt [][4]
- 函数指针:允许在不同的时间传递不同的函数的地址
- double(*pf)(int) double pam(int) -> pf = pam
- 第八章 函数探幽
- 内联函数: inline double square(double x) {return x * x ;} 直接替换:将a=square(1.0)替换成a=1.0 * 1.0
- 引用接近const指针
- 如果函数调用的参数不是左值或与相应的const引用参数的类型不匹配,则c++将创建类型正确的匿名变量,将函数调用的参数的值传递给改匿名变量,并让参数来引用变量
- 使用const可以避免无意修改数据;能使函数处理const和非const实参,否则只能接收非const数据;使函数能够正确生成并使用临时变量
- 默认参数:int harpo(int n, int m = 4 , int j = 5):只能从右向左添加默认参数,调用的时候也不能跳过某一个参数
- 函数重载的关键是函数的参数列表–也称为函数特征标(function signature),将类型引用和类型看作是一个特征标,即double x 和 double & x 是同一个特征标,返回类型不算特征标,将非const值赋给const变量是合法的,反之是非合法的
- 注意:对于非引用变量类型来说,形参中有没有const都是一样的,因为它会复制实参到形参中,所以void mys(int a)这里面有没有const都是一样的
- template或template
- c++允许将一个结构赋值给另一个结构(struct)
- 显示具体化:特殊的template;一般先找非模板版本,再找显示具体化版本,再找模板版本;写法:template<>void swap(job & , job &)或template<>void swap(job & , job &)
- 显示实例化:template void swap)(int,int),让编译器生成一个int型的函数定义(不需要重新写)
- 编译器选择函数版本的策略:1. 创建候选函数列表 2. 使用候选函数列表创建可行函数列表,这些都是参数数目正确的函数 3. 确定是否有最佳的可行函数
- 调用的时候可以显示指明模板函数的类型,比如lesser(x,y)
- decltype(x+y)xpy:让xpy定义成和x+y相同的类型
- double && r : 可以匹配右值,比如x+y
- 第九章 内存模型和名称空间
- 头文件用<>:在存储标准头文件的主机系统的文件系统中查找;使用" "的话会在当前的工作目录或源代码目录中查找
- 避免多次包含同一个头文件:
#ifndef COORDIN_H #define COORDIN_H #endif
- 链接性(linkage)描述了名称如何在不同单元间共享,链接性为外部的名称可在文件间共享,链接性为内部的名称可以在一个文件中的函数间共享,也有无链接性
- 全局作用域也叫文件作用域
- 自动存储持续性:在程序开始执行其所属的函数或代码块时被创建,在执行完函数或代码块时,使用的内存被释放,只在包含他们的函数或代码块中可见
- 自动变量被存在栈中,参数也被存在栈中
- 静态变量:编译器将分配固定的内存块来存储所有的静态变量,这些变量在整个程序执行期间一直存在,如果没有显示地初始化静态变量,将被设置为0
- 函数外int global = 1000 为外部链接性,static int a = 50 为内部链接性 , 函数内static int b = 50为无链接性
- 定义和声明:变量只能定义一次,如果在另一个文件中使用全局变量的话,需要使用extern int blem这种声明,声明不分配内存空间,定义会分配内存空间
- 静态外部变量会隐藏常规外部变量(也就是说他俩可以重名)
- volatile:告诉编译器一个变量是随时可变的(如硬件可以改变某个变量),可以阻止编译器的优化(将变量的值存在寄存器中下次用的时候直接读取)
- mutable:即使结构或类变量为const,其中某个mutable成员也可被修改
- 全局const定义就像使用了static一样,为内部链接性
- 如果希望某个常量的链接性为外部:extern const int a = 1
- 函数的链接性默认是外部的,在另一个文件需要先用extern void mys(int a)声明后才能使用,想整成内部的可以static void mys(int a)
- 通常编译器使用三块独立的内存:一块用于静态变量,一块用于自动变量,一块用于动态存储
- using声明:using JILL::fetch
- using编译指令:using namespace std
- 第10章 对象和类
- OOP:抽象,多态,继承
- 构造函数是用来构造函数的
- 显式调用构造函数:stock food = stock(1,2)
- 隐式调用构造函数:stock food(1,2)
- 如果没有提供任何构造函数,c++将自动提供默认构造函数
- 定义默认构造函数的两种方式:1. 给已有的构造函数的所有参数提供默认值:stock(const string & co = “error”,int n = 0,double pr = 0.0) 2.stock()再写定义
- 析构函数:~stock():主要是为了delete对象new出来的空间,如果没有提供析构函数,c++将提供一个默认构造函数(当对象要消失的时候就会调用析构函数)
- 如果stock stock1之前已存在,stock1 = stock(1,2)就不是对stock1的初始化,而是通过构造函数创建一个新的临时的对象复制给它的操作
- const成员函数:void show() const:保证了对象不会被修改
- return *this返回对象本身 return this 返回this指针
- 对象数组:stock mystuff[4]
- 类里面的const int month = 12 ; double cost[month] ; 是不行的,因为类声明只描述了对象的形式,并没有创建对象
- 如果想用的话需要创建一个枚举,类声明中的枚举的作用域为整个类,而且所有对象的数据成员中都不会有枚举,所以可以enum{month = 12} ; double cost[month] ;在作用域为整个类的代码中遇到它时,编译器将用12替换他(只是创建了符号常量)
- 或者static const int month = 12 ; double cost[month] ;也行,这样的话month常量会与其他静态变量储存在一起
- 作用域枚举:目前不是很懂
- 第11章 使用类
- 运算符重载:假如a,b,c都是同一个类的不同对象,a=b+c相当于a=b.operator+©
- Time operator+(const Time & t) const
- 友元函数:解决a=b2.5可以但a=2.5b不可以的问题:2.75不是对象,编译器不能用成员函数调用来替换该表达式,需要创建一个非成员函数,而且要有访问类中访问成员的权限,所以有了友元函数,friend Time operator*(double m ,const Time &t),友元函数不是成员函数,不能使用成员运算符来调用,两个操作数都按参数传入
- 状态成员:enum Mode{rect,pol} Mode mode ; 此时这个mode就是个状态成员,它的值可以为rect或者pol
- 强制类型转换:int * p = 10 不合法,因为数字默认不能直接赋给指针,但int * p = (int *) 10合法,因为给10转成了指针类型
- stonewt mycat ; mycat = 19.6 ; 这个是隐式转换,调用了stonewt(double);而explicit关键字如explicit stonewt(double a)会关闭隐式转换,只剩下显式转换;构造函数只能将某种类型转换为类类型
- 转换函数:将类类型转换成某种类型(一种特殊的运算符函数)operator typename();(需要声明在类中,一般要声明成explicit的)
- 自动应用类型转换遇到多个转换函数时会报错,但如果只有一个转换函数,编译器会接受
- 第12章 类和动态内存分配
- 静态类成员:只创建一个静态类变量副本
- 复制构造函数(参数是对象);复制运算符(类中没定义时会有一个默认的赋值运算符)
- 静态类成员函数:不能用对象调用,不与特定的对象关联,只能使用静态数据成员
- 返回对象会调用复制构造函数,而返回对象引用不会
- 返回const对象可以解决 net = a + b ; 与 a + b = net 都成立的问题,第二种将a+b存为临时变量,又被赋值成net了,之前的临时对象就没了,返回vector const 就能解决这一问题
- 成员初始化列表:classy::classy(int n , int m) : mem1(n) , mem2(2) (mem1 mem2分别为类的成员)
- 第13章 类继承
- class a : public b
- 派生类对象存储了基类的数据成员
- 派生类对象可以使用基类的方法
- 派生类需要自己的构造函数,可以根据需要添加额外的数据成员和成员函数
- 派生类不能直接访问基类的私有成员,只能通过基类提供的类方法进行访问
- 派生类的构造函数例子:a::a(unsigned int r , const string& fn , const string& ln,bool ht) : b(fn,ln,ht) (最后这个:是成员初始化列表)
- 创建派生类对象时,先调用基类构造函数,再调用派生类构造函数,派生类对象过期时,先调用派生类析构函数,再调用基类析构函数
- 可以将基类指针或引用指向派生类对象,但只能调用基类方法;反过来不行,因为基类对象不支持一些派生类函数
- 虚函数:可以根据指针或引用指向的对象的类型选择成员函数,而不是根据指针或对象的类型选择
- 非构造函数不能使用成员初始化列表语法
- 虚析构函数:确保了正确的析构函数序列被调用
- 将函数调用解释成执行特定的函数代码块被称为函数名联编(binding),有静态联编和动态联编
- 向上强制转换被允许:brass指针可以指向brassplus对象;向下强制转换不被允许
- 编译器对非虚方法进行静态联编,对虚方法使用动态联编
- 虚函数的原理:每个对象都有一个隐藏成员:虚函数表(vtbl),是一个指针,指向vtbl,存储了每个对象对应的函数地址
- 一般protected用于函数,不用在数据变量上,要不然容易被派生类整出来的函数更改数据变量的值
- 抽象类:有纯虚函数,virtual void a() = 0,不能创建对象
- 当基类和派生类都采用动态内存分配时,派生类的析构函数,复制构造函数,赋值运算符都必须使用相应的基类方法来处理这些基类元素
- 第14章 c++中的代码重用
- 将typedef放在类的private中可以让整个类内使用这个别名
- explicit可以防止单参数构造函数的隐式转换
- 类中首先被声明的成员会先被初始化
- 私有继承:基类的接口只能在派生类内部使用,在派生类中不再作为接口出现,会将基类的公有成员和保护成员都变成自己的私有成员
- 使用包含时将使用对象名来调用方法,使用私有继承时将使用类名和作用域解析符来调用方法
- 使用私有继承时可以用强制类型转换来访问基类对象
- 通常应用包含来建立has-a关系,如果新类要访问原有类的保护成员,或重新定义虚函数,则应使用私有继承
- 保护继承:会将基类的公有成员和保护成员都变成自己的保护成员
- class a : public b , public c多重继承,如果第二个public没写的话会默认成private
- 虚基类:使得从多个类(他们的基类相同)派生出的对象只继承一个基类对象,class a : virtual public b
- c++在基类是虚的时,禁止信息通过中间类自动传递给基类 p558
- 可以singwait(const worker &wk ,int p = 0 ,int v - sing::other) : worker(wk),wait(wk,p),sing(wk,v)
- 使用虚基类时,派生类中的名称优先于直接或间接祖先类中的相同名称,比如class B 和class V:virtual public B , class C:public V,直接调用同名方法时,会调用V的方法
- 模板类:前面加template template 使用时:stack::a()
- 模板不是定义,是说明了如何生成定义的编译器指令
- 默认类型模板参数:template<class T1,class T2 = int>class A
- 模板的具体化:隐式实例化;p582;显示实例化:template class A<string,100>;显示具体化:template<>class A;部分具体化:templateclass A<T ,int >
- 成员模板:可以将模板类和模板函数作为成员
- 将模板用作参数p586
- 模板类和友元p588
- 第15章 友元,异常和其他
- 友元类:友元类的所有方法都可以访问原始类的私有成员和保护成员
- 剩下的内容暂时先略过,以后再看(从15.2嵌套类开始的内容)