C++ -- 虚函数与多态

1 虚函数相关知识

1.1 虚函数概念

1.定义:在一个类的成员函数前面加上virtual关键字,则该函数就称为虚函数。
2.如果一个函数不是类的成员函数,则该函数不能定义为虚函数。(即就是类外面不能使用virtual关键字)

  • 虚函数中有一个特殊的虚函数:纯虚函数
1.2 纯虚函数与抽象类

1.纯虚函数:在虚函数的后面加上=0;

virtual void Display() = 0;

2.包含纯虚函数的类称为抽象类,抽象类不能实例化出对象;
这里写图片描述

3.如果一个类继承了抽象类,则该类也变成了抽象类(因为这个类继承了抽象类里面的纯虚函数),如果该派生类想实例化出对象,则该派生类必须重写这个纯虚函数;重写之后父类仍然不能实例化出对象,只有子类才可以。所以将抽象类称为接口类,保证了只要将父类的虚函数定义成纯虚函数,则其子类必须重写这个虚函数。

例如:Student类重写了Person类的虚函数Display,则子类可以示例化出对象。
这里写图片描述

2 多态

1.多态就是多种形态;
2.多态的分类:静态多态和动态多态

2.1 静态多态

在系统编译期间就可以确定程序执行到当前位置需要执行哪个函数,例如C++中的函数重载与泛型编程就属于静态多态。

2.2 动态多态

在系统编译期间并不确定该程序需要执行哪个函数,只有在程序运行时才确定执行哪个函数。C++采用虚函数实现动态多态。

2.3 多态的构成条件

①父类对象的指针或引用;
②虚函数的重写。

2.3.1 重写

在不同的作用域下(一个在父类一个在子类)两个函数的函数名,参数,返回值完全相同(协变除外)。

  • 协变:父类和子类的两个虚函数,函数名相同,参数也相同,但返回值一个返回父类对象的指针(或引用),一个返回子类对象的指针(或引用)
    构成协变的代码:
class AA
{
public:
      virtual AA* fun1()
      {
           cout << "AA::fun1()" << endl;
           return this;
      }

private:
      int _a;
};

class BB :public AA
{
public:
      virtual BB* fun1()
      {
           cout << "BB::fun1()" << endl;
           return this;
      }

private:
      int _b;
};

int main()
{
      AA a;
      BB b;
      AA* p = &a;
      p->fun1();
      p = &b;
      p->fun1();
      system("pause");
      return 0;
}
2.4 构成多态的示例:
class Person
{
public:
      virtual void BuyTicket()
      {
           cout << "买票--全价" << endl;
      }
protected:
      string _name;
};

class Student :public Person
{
public:
      virtual void BuyTicket()
      {
           cout << "买学生票--半价" << endl;
      }
protected:
      int _num;
};
int main()
{
      Person* p;
      Person a;
      Student s;
      p = &a;
      p->BuyTicket();  //指向父类,调用父类的函数

      p = &s;  //切片行为 ,指向子类,调子类的函数
      p->BuyTicket(); 
      system("pause");
      return 0;
}

运行结果如下:
这里写图片描述

2.5 不构成多态的场景:

场景1:没有虚函数的重写

class Person
{
public:
      void BuyTicket()  //由于父类没有加上virtual关键字,不构成虚函数重写
      {
           cout << "买票--全价" << endl;
      }
protected:
      string _name;
};
class Student :public Person
{
public:
      void BuyTicket()
      {
           cout << "买学生票--半价" << endl;
      }
protected:
      int _num;
};
int main()
{
      Student s;
      s.BuyTicket();  //因为Person类和Student类中有同名的Display函数,这个函数两个类中都没有加上virtual关键字,构成覆盖,就只会调用子类的BuyTicket函数。
      system("pause");
      return 0;
}

场景2:没有父类对象的指针或引用

class Person
{
public:
      virtual void BuyTicket()
      {
           cout << "买票--全价" << endl;
      }
protected:
      string _name;
};
class Student :public Person
{
public:
      virtual void BuyTicket()
      {
           cout << "买学生票--半价" << endl;
      }
protected:
      int _num;
};
int main()
{
      Person p;  //构成多态与对象有关,指向什么对象,就调用那个对象改写的虚函数,不构成多态与类型有关
      p.BuyTicket();  //没有父类对象的指针或引用,不构成多态则与类型有关,它是Person类的,则调用Person类的BuyTicket函数
      Student s;
      s.BuyTicket();  //它是Student类的,则调用Student类的BuyTicket函数
      system("pause");
      return 0;
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页