模板(TEMPLATE)
模板时泛型编程的基础,泛型编程就是与1类型无关的编程,可以提高软件的重用
函数模板
类模板
定义对象时必须传递类型
在类外定义成员函数时要写模板参数列表
模板参数
模板的模板参数,实现容器适配器
非类型的模板参数
全特化与编特化
全特化后在定义车成员函数不需要模板参数
全特化和偏特化都是在模板的基础上,不能单独存在
类型萃取
基于模板的全特化,区分内置类型和自定义类型
模板的分离编译
因为编译和链接是分开的,所以将声明和定义单独编译时,链接会出错
将声明和定义放到一个“xxx.cpp”的头文件里面
强制类型转换
static_cast
static_cast用于非多态类型转换(静态转换),任何标准类型都可以使用它。它只能用于两个关联的类型转换
reinterpret_cast
reinterpret_cast用于将一种类型转换成另一种不同的类型。只能转化不相关的类型
const_cast
const_cast删除变量const属性,方便赋值
dynamic_cast
将一个父类的指针或引用转换成一个子类的指针或引用(动态转换)。如不能转换则返回空
explicit 防止构造函数隐式类型转换
异常处理
当函数发现一个自己无法处理的错误时,抛出异常,由函数的调用者处理
try/throw/catch
异常的捕捉是根据类型决定的,而不是根据对象决定的
抛出的异常会被离它最近的,且类型相同的catch捕获,要是没有捕获,则程序会自动结束掉
异常会改变程序执行的流程,会带来一系列的问题。异常的使用有栈展开的过程,会降低程序效率
数据类型
基本(内置)数据类型
语言内部已经定义的类型称为内置类型
字符char
整形 int
浮点型 float/double
逻辑型 bool
无类型 void
非基本类型
数组 ,指针,struct,union,enum,class
在C++中struct和class除了默认的访问属性不同外,其余基本相同
C++ 中公有63个关键字
继承
继承关系
公有继承(public)
基类除私有成员外,其他成员访问属性不变,私有成员在子类中不可访问
保护继承 (protected)
基类中公有和保护成员在子类中都是保护的,基类的私有成员在子类中是不可访问的
私有继承 (private)
基类的公有和保护成员在子类中是私有的,基类的私有成员在子类中是不可访问的
赋值兼容规则
子类对象可以给父类对象赋值,父类对象不能给子类对象赋值
父类的指针或引用可以指向子类对象,子类的指针或引用不能指向父类对象
继承过程中的作用域
在继承体系中基类和派生类都有独立的作用域
如果派生类中有和基类同名的成员,则子类成员会将基类成员进行“隐藏”,要想访问基类成员则必须加上基类的类域限定
派生类中如果没有定义类默认的六个成员函数,则派生类会自己合成
单继承&多继承
单继承:一个子类只有一个父类
多继承:一个子类有两个或两个以上的父类 (用的很少)
菱形继承
菱形继承会导致数据沉余和二义性的问题
虚继承可以解决菱形继承所带来的问题
多态
允许用同样的接口来实现不同的功能,即“一个接口,多个方法”。这种在函数执行期间才确定所调用的对象,称为动态多态,动态多态实现基于赋值兼容规则和虚函数
虚函数(virtual)
在类的成员函数前加 virtual ,则这个函数局势虚函数
如果在一个类中声明虚函数,那么在这个类之后的继承体系中这个函数都是虚函数
重写
如果在子类中定义了父类中的虚函数,则成为 重写(覆盖)
重新(覆盖)是虚函数表中虚函数地址的覆盖
重写必须在不同的作用域中,在父类和子类中,父类中还必须有虚函数
重写要求函数名,函数参数,返回值必须相同 (协变除外)
纯虚函数
在虚函数的后面写=0,则这个虚函数就是纯虚函数,纯虚函数只有声明
含有纯虚函数的类叫抽象类(接口类),不能实例化对象。只有在派生类中实例化纯虚函数后才可以实例化对象
C++对象模型&虚函数表
内存管理
nwe/delete
new:先调用operator nwe 开辟空间,在调用构造函数
delete:先调用析构函数,在调用operator delete 释放空间
nwe[]/delete[]
new[]会开辟4个字节来存放要开辟空间的个数
new[]:先调用operator new[] ,在调用构造函数
delete[] 先析构,在调用 operator delete[]
定位 new 表达式
在以分配的空间中调用构造函数初始化一个对象
new/delete 和malloc/free的区别
malloc 需要计算开辟的大小,而且还要对返回值进行强制类型转换
nwe 不需要计算大小,而且返回值类型不需要转换
malloc 开辟空间失败返回空,new 则抛出异常
malloc/free 是函数,new/delete 是关键字
nwe/delete 会自动调用构造和析构函数
深度解析 new/delete和new[]/delete[]
智能指针
智能指针是用来管理资源的分配以及回收的
scoped_str/scoped_array/unique_ptr
shared_ptr/share_array/weak_ptr
share_ptr 循化引用所产生的缺陷
定置删除器
重载
重载又称为静态多态(绑定),编译期间确定所调用的函数
由于有重载,所有C++和C的函数命名方式不同,所以在引用C文件时写成 extern“C”
函数重载
要在同一作用域
函数名相同,参数类型或参数个数不同,返回值可同可不同
重载的引入是为了减少对函数名字的记忆,所以良好的习惯是将功能类似的函数才实现成重载
运算符重载(operator)
输入输出操作符重载
声明为友元函数进行重载
返回值是输入流或输出流对象的引用
第一个参数是输入输出流对象的引用
不能重载的操作符
* /: : /sizeof/?: /
指针&引用&const
引用
一个变量可以有多个引用
引用不分配空间,引用只是变量的别名
引用必须初始化
引用从一而终,只能在初始化的时候引用一次
不能通过const修饰的引用改变变量的值
引用可以作为参数传递,是实参的别名
如果不改变变量的值,尽量使用常引用传参
引用与指针的区别
引用只能在初始化的时候引用一次,指针的值可变
引用必须初始化,指针可以为空
指针的大小固定,引用的大小是变量的大小
在对引用自增和自减是引用所代表的空间的之发生变化,而指针自增自减时指针指向的位置发生变化
引用比指针更高效,更灵活
const 修饰变量
编译器把它当作常量,每次从寄存器中取值
浅拷贝与深拷贝&写时拷贝
实现一个 string
Copy On Write 的实现原理 --- 引用计数