一、虚函数
定义:被virtual 修饰的成员函数叫虚函数,主要用来实现多态;
格式:virtual 返回值 函数名(参数列表) { }
注意: 只要在父类中写了virtual 子类中的相同函数不写virtual也是虚函数;
(父类和子类写了一个一模一样的函数,但函数体不一样)
二、多态:
定义:用父类的指针(引用)指向子类的对象,会调用子类的方法;
要求:必须要有继承关系,有父子类关系;
子类需要重写父类的方法(父类需要有虚函数);
父类的指针(引用)指向(引用)子类的对象;
虚函数表:
要有虚函数,在创建类的时候会自动创建虚函数表;
虚函数表存放了最终需要调用的虚函数的地址,这个表叫做虚函数表
三、纯虚函数
场景:多态中,子类定义了父类的虚函数,父类的虚函数永远调用不了,没必要写函数体
提供接口,给子类实现的时候使用;
格式: virtual 返回值 函数名(参数列表) = 0;
注意:如果在类中定义纯虚函数,则这个类叫做抽象类;
抽象类没法定义对象,也就是无法实例化对象;
子类必须重写父类的抽象方法,否则子类也是抽象类;
抽象方法没有函数体,只是用来定义接口;
抽象类中可以有成员变量,也可以有普通函数,也可以有虚函数;
接口类:全部是抽象方法的类叫做接口类
关键总结:(子类继承父类)
第一种:如果父子类之间都写了相同的普通函数(没有虚函数),通过父类的对象调用
的父类函数,通过子类对象调用的是子类的函数,如果通过父类的指针指向
子类,调用的是父类的函数;
第二种:如果父子类之间都写了虚函数函数,通过父类的对象调用父类函数
通过子类对象调用的是子类的函数;
如果通过父类的指针指向子类,调用的是子类的函数;(多态)
第三种:如果父类写了virtual,子类相同函数没写virtual,和第二种一样
第四种:如果父类没写virtual,子类写了virtual函数,如果通过父类的指针指向子类
调用的是父类的普通函数,不构成多态;
第五种:父类写了virtual函数,子类没有写函数;调用的都是父类的;
四、虚析构
问题:在多态使用时,如果子类中有另外开辟空间,那么父类指针调用的是父类的析构
没有调用子类析构,导致子类内存没释放,内存泄漏
解决:将父类的析构定义的虚函数,或者纯虚函数,实现多态的效果
格式: vritual ~类名(){}
virtual ~类名() = 0;
注意:用来解决通过父类指针释放子类对象的问题的
如果父类的析构是纯虚函数,则子类一定要实现析构,并且不可以构建父类对象
只有子类重写申请了内存(int*q)才需要用到虚析构;
五、虚继承
作用:主要是用来解决菱形继承问题
菱形继承的问题:
孙子类从爷爷类继承了多个相同的成员变量和方法;
格式:class 派生类: virtual public 基类{};
六、字符串string
1.string的本质:string是c++风格的字符串,是一个类;也叫作容器;
2.string和char*的区别:
Char* 是c语言中的指针,指向的字符串,
String是一个类,内部封装了char*, string有很多的成员函数来操作char*
3.构造函数
string() ; string temp;
String(char*); string temp(“abcd”);
String(int num,char x); string temp(10,’a’);
String(const string& other); string temp(str);
4.字符串赋值
String& operator=(const string& x);
String& operator=(const char x);
String& operator=(const char* x);
String& assign(const string& x); 也是赋值处理,只是通过函数的方式实现
5.字符串拼接
String& operator+=(const char* s);
String& operator+=(const char s);
String& operator+=(const string& s);
String& append(const char* s);
String& append(const char s);
String& append(const string& s);
6.字符串的查找
int find(const string& str,int pos = 0); //从pos的位置开始查找str,返回首字母位置
int find(const char* str,int pos = 0); //从pos的位置开始查找str字符串是否存在
int find(const char str,int pos = 0); //从pos的位置开始查找str字符串是否存在
Int rfind(const string& str,int pos= 0)//从pos的位置从后往前查找,返回查找位置
rfind的没找到的返回值是-1
7.字符串的比较
int compare(const string&x)const ;//字符串比较,成员函数,需要用点的方式访问
int compare(const char*x)const ;
七、文件操作
- 文件分类:文本文件 二进制文件
- 操作:文件的读(ifstream) 文件的写(ofstream) 文件的读写(fstream)
- 文件的写操作
添加头文件#include <fstream>
创建流对象:ofsream ofs
打开文件 ofs.open(“路径”,打开方式) ; 多个打开方式可以用 | 操作
打开方式: ios::in 读的方式打开文件
Ios::out 只写的方式打开文件
Ios:app 追加的方式打开文件
Ios::trunc 文件存在则清空
Ios::binary 二进制文件
以只写的方式追加打开二进制文件
ofs.open(“danny”,ios::out|ios::app|ios::binary);
写文件: ofs << “字符串” ; ofs<< 变量
关闭文件:ofs.close();
4.读文件
添加头文件#include <fstream>
创建流对象:ifsream ifs;
打开文件 ifs.open(“路径”,打开方式) ; 多个打开方式可以用 | 操作
打开方式: ios::in 读的方式打开文件
Ios::out 只写的方式打开文件
Ios:app 追加的方式打开文件
Ios::trunc 文件存在则清空
Ios::binary 二进制文件
以只写的方式追加打开二进制文件
ofs.open(“danny”,ios::out|ios::app|ios::binary);
判断是否打开成功: if(ifs.is_open()){ };如果成功返回1,失败返回0
读文件方式1: ifs >> buf ; 开文件开头开始读取,独到内存中
读文件方式2: getline(str,n,ch)文件流中接收 n-1 个字符给 str ,当遇到指定 ch 字符时会停止,默认 ch 为 '\0'
读文件方式3: get() 从文件流中读取一个字符,同时该字符会从输入流中消失
如果结束,get()返回EOF
关闭文件:ifs.close();