c++ 虚函数、多态、纯虚函数、虚析构、虚继承、文件操作

一、虚函数

定义:被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 ;

七、文件操作

  1. 文件分类:文本文件   二进制文件
  2. 操作:文件的读(ifstream)  文件的写(ofstream)  文件的读写(fstream)
  3. 文件的写操作

   添加头文件#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();

猜你喜欢

转载自blog.csdn.net/m0_74889801/article/details/128650482