一.虚函数表
什么是虚函数表,在C++的类中,一旦成员函数中有虚函数,这个类中就会多一个虚函数表指针,这个指针指向一个虚函数表,表里面记录这个类中所有的虚函数,
当这个类被继承(不管子类中有没有虚函数),它的子顺序中也会有一个虚函数表,
如果子类的成员函数中的有函数签名与父类的虚函数一样就会用子类中的函数替换它在虚函数表中的位置,就达到覆盖的效果
当通过类指针或引用调用函数时,会根据对象中实际的虚函数表来调用函数,这样就达到了多态的效果
二.虚析构
当使用delete释放一个父类指针时,不管实际指向的对象是子类还是父类都只会调用父类的析构函数(多态肯定会出现问题)
如果子类的析构函数有需要负责释放的内存,就会造成内存泄露
为了解决这个问题,可以把父类的析构函数设置为虚函数,析构函数进行覆盖时不会比较函数名
当父类的析构为虚函数时,通过父类指针或引用释放子类对象时,会自动调用子类的析构函数,子类的析构函数执行完成后也会调用父类的析构函数
注意:析构函数可以为虚函数,但构造函数不可以
三.强制类型转换
注意:C++中为了兼容C语言,(目标类型)源类型,依然可以继续使用,但C语言的强制类型转换安全性差,因此建议使用C++中的强制类型转换
注意:C++之父认为如果代码设计的完善,根据不需要用到强制类型转换,而C++的强制类型转换之所以设计的很复杂,是为了让程序多关注代码本身的设计,尽量少使用
C++中的强制类型转换保证没有很大安全隐患
static_cast<目标类型>(源类型) 编译器对源类型和目标类型做兼容性检查,不通过则报错
dynamic_cast<目标类型>(源类型) 编译器会对源类型和目标类是否同为指针或引用,并且存在多态型的继承关系
const_cast<目标类型>(源类型) 编译器会对源类型和目标类是否同为指针或引用,除了常属性外其他必须完全相同,否则报错
reinterpret_cast<目标类型>(源类型) 编译器会对源类型和目标类是否为指针和整数进行检查,也就是说把整数转换成指针或把整数转换成指针;
静态编译:指针或引用的目标是确定的,在编译时间就经过所有类型检查,函数调用
动态编译: 指针或引用的目标是不确定的(多态),只有函数调用时候才确定,具体是哪个子类
四.I/O流
I/O流的打开方式:
ios::in 以读权限打开,不存在则失败,存在不清空
ios::out 以写权限打开,不存在则创建,存在则清空
ios::app 打开文件用于追加,不存在则创建,存在不清空,追加到文件开头
ios::binary 以二进制模式进行读写
ios::ate 打开时定位到文件末尾
ios::trunc 打开文件时清空
fstream/ifstream/ofstream 类用于进行文件操作
构造函数或成员函数 open用于打开文件
good成员函数检查流是否可用
eof成员函数用于输入流是否结束
>>操作符用于从文件中读取数据到变量
<<操作符用于输入数据到文件
IO流有一系列格式化控制函数,类似:左对齐,右对齐,宽度填充,小数点位数
二进制读写:read/write
read(char_type*_s,streamsize_n)
gcountc()成员函数可以获取上次流的二进制读操作的字节数
write(char_type*_s,streamsize_n)
good()成员函数可以获取到写操作是否成功
随机读写:seekp(off_type,ios_base::seekdir)
功能:设置文件的位置指针
off_type:偏移值
正值向右,负值向左
seekdir:基础位置
ios::beg 文件开头
ios::cur 当前位置
ios::end 文件末尾
tellp()成员函数
该成员函数返回当前文件流的位置指针(字节数);
五.类型信息 typeid
用于获取数据的类型信息,返回type_info
name成员函数,可以获取类型的名字,內建类型名字使用缩写
同时还支持== !=用来比较是否是同一类型
如果用于判断父子类的指针或引用,它不能准确判断出实际的对象类型
但可以判断具有多态继承的关系的父子类的指针或引用,它的实际对象
sudo find/-name filename
sudo find/|grep "std"
grep 'Base' * 当前目录查找文件中包含的字符
grep -r 'Base' * 当前目录查找文件中包含的字符,包括所有子级目录
grep -r 'Base' * dir 指定目录下查找文件中包含的字符,包括所有子级目录
六.异常处理
抛异常
throw 数据
抛异常对象
抛异常类型
注意:不能抛出局部对象的指针可引用
注意:如果异常没有被捕获处理,程序就会停止
捕获异常
try{
可以抛出异常的代码
}
catch(类型 变量名)//根据数据类型进行捕获
{
处理异常,如果无法处理可以继续抛出异常
}
注意:捕获异常的顺序是自上而下的,而不是最精准的匹配,针对子类的异常捕获时要放在父类的前面
函数的异常声明:
返回值类型 函数名(参数列表) throw(类型1,类型2,…)
注意:如果不写异常声明表示什么类型的异常都可能抛出,一旦超出异常声明的范围,程序会直接停止,无法捕获
注意:throw()表示什么类型都不会抛出
设计异常类:
class Error
{
int errno;
char errmsg[255];
public:
Error(int errno=-1,const char* msg="未知错误" )
{
this->errno=errno;
strcpy(errmsg,msg);
}
int getError(void)
{
return erron;
}
const char* getErrmsg(void)
{
return errmsg;
}
}