一、多态、继承
1、C++允许父子之间的类型转换,不需要作强制类型转换,父类的引用或指针可以直接指向子类对象;
2、地址早绑定:在编译阶段确定函数地址
3、地址晚绑定:在程序运行阶段确定函数地址。
4、动态多态满足条件:
- 有继承关系
- 子类重写父类中的虚函数
- 父类的指针或引用指向子类对象
5、多态原理
由于类中定义了虚函数,类的结构发生改变,类中会保存一个虚函数指针(vfptr)指向虚函数表,虚函数表用来存放虚函数地址。
当子类继承父类,没重写父类虚函数之前,除了继承父类虚函数之外,还会继承父类的虚函数指针,虚函数指针指向的虚函数表,存放的是父类虚函数地址。
当子类重写父类虚函数之后子类中的虚函数表内部会把父类虚函数地址替换成子类的虚函数地址。
//父类的指针或引用指向子类对象
Animal &animal = cat;
animal.speak();
当调用时,传的是哪个对象,就调用哪个对象虚函数表中的虚函数。
6、查看类内部结构:打开vs2015开发人员命令提示工具,cd到类所在文件夹,dir打开目录之后输入命令:d1 reportSingleClassLayou类名称“文件名”,即可查看。
7、类成员函数为纯虚函数的类称为抽象类,抽象类特点:
- 无法实例化对象,无论是堆区还是栈区。
- 子类必须重写抽象类中的纯虚函数,否则也属于抽象类。
8、虚析构和纯虚析构
问题描述:多态使用时,父类指针或引用指向子类对象,父类指针或引用在释放时无法调用到子类的析构代码。如果子类中有属性在堆区开辟内存,那么将会造成内存泄漏。
解决:将父类中的析构函数改为虚析构或纯虚析构。
虚析构和纯虚析构共性:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
虚析构和纯虚析构区别:
- 如果是纯虚析构,该类属于抽象类,无法实例化对象。
二、文件操作
C++中对文件操作需要包含头文件fstream
文件类型:
- 文本文件:文件以文本的ASCLL码形式存储在计算机中
- 二进制文件:文件以二进制的形式存储在计算机中。
操作文件三大类:
- ofstream:写操作
- ifstream:读操作
- fstream:读写操作
2.1、文本文件
2.11、写文件
写文件步骤:
- 包含头文件:
#include <fstream>
- 创建流对象:
ofstream ofs;
- 打开文件并判断文件是否打开成功:
ofs.open("文件路径",打开方式);
- 写数据:
ofs<<"写入的数据";
- 关闭文件:
ofs.close();
读文件步骤:
- 包含头文件:
#include <fstream>
- 创建流对象:
ifstream ifs;
- 打开文件并判断文件是否打开成功:
ifs.open("文件路径",打开方式);
- 读数据,四种方式读取:
//1、一行一行读取
char buf[1024] = {0};
while(ifs>>buf);
//2、一行一行读取
char buf[1024] = {0};
while(ifs.getline(buf,sizeof(buf)));
//3利用全局函数getline
#include <string>
string buf;
while(getline(ifs,buf));
//4、一个字符一个字符读,直到文件尾
char c;
while((c = ifs.get()) != EOF);
- 关闭文件:
ofs.close();
二进制文件-写文件:
二进制方式写文件主要利用流对象调用成员函数write
函数原型:
ostream& write(const char *buffer,int len);
函数解释:字符指针buffer指向内存中的一段存储空间,len是读写的字节数
class Person
{
public:
char name[64];
int age;
};
int main()
{
//创建流对象
ofstream ofs("test.txt", ios::out | ios::binary);
//打开文件
//ofs.open("test.txt", ios::out | ios::binary);
//判断
if (!ofs.is_open())
{
cout << "文件打开失败!" << endl;
return;
}
//写文件
Person p = { "张三",18 };
ofs.write((const char *)&p, sizeof(Person));
//关闭文件
ofs.close();
system("PAUSE");
return 0;
}
二进制文件-读文件:
二进制方式写文件主要利用流对象调用成员函数read
函数原型:
ostream& read(char *buffer,int len);
函数解释:字符指针buffer指向内存中的一段存储空间,len是读写的字节数
class Person
{
public:
char name[64];
int age;
};
int main()
{
//创建流对象并设置文件打开方式
ifstream ifs("test.txt", ios::in | ios::binary);
//打开文件
//ifs.open("test.txt", ios::out | ios::binary);
if (!ifs.is_open())
{
cout << "文件打开失败!" << endl;
return;
}
//读取文件
Person p;
ifs.read((char *)&p, sizeof(Person));
cout <<"姓名:"<< p.name <<",年龄:"<< p.age << endl;
ifs.close();
system("PAUSE");
return 0;
}
文件打开方式:
打开方式 | 解释 |
---|---|
ios::in | 为读文件而打开文件 |
ios::out | 为写文件而打开文件,文件不存在则创建 |
ios:: ate | 初始位置:文件尾 |
ios::app | 追加方式写文件 |
ios::trunc | 如果文件存在先删除再创建 |
ios::binary | 二进制方式 |
注意:文件打开方式可以配合使用,利用|操作符
例如:使用二进制方式写文件而打开文件:
ios::binary | ios::out