半小时掌握C++11之多态1

95 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

多态概念

多态字面意思就是多种形态。

比如学生,成人、军人都属于人这个类。但买票时,成人买票全价,如果是学生那么半价,如果是军人,就可以优先买票。不同的人买票会有不同的实现方法,这就是多态。

C++中多态

C++的多态必须满足两个条件: 1 必须通过基类的指针或者引用调用虚函数 2 被调用的函数是虚函数,且必须完成对基类虚函数的重写

虚函数

用virtual修饰的关键字就是虚函数。 虚函数只能是类中非静态的成员函数

virtual void fun() 
{}
​
#include <iostream>
using namespace std;
class Person //人
{
  public:
  virtual void fun()
   {
       cout << "全价票" << endl; //成人票全价
   }
};
class Student : public Person //学生
{
   public:
   virtual void fun() //子类完成对父类虚函数的重写
   {
       cout << "半价票" << endl;//学生票半价
   }
};
class Soldier : public Person{
   public:
   virtual void fun() 
   {
       cout << "军人票" << endl;
   }
};
​
int main()
{
   Person* p1 = new Person;
   p1->fun();
   p1 = new Student;
   p1->fun();
   p1 = new Soldier;
   p1->fun();
   return 0;
}
/*
全价票
半价票
军人票
*/

虚函数的机制

可以使用父类类型的指针变量,里面存储子类对象的地址

Person* p1;先修一个名字叫p1的房子,用来放Person类型的地址

p1 = new Student;修一个Student类型的房子,并把Student类型的房子的地址放到p1里面去。所以运行时运行的时Student类的成员函数

p1 = new Soldier;同理

int main()
{
   Person p1;
   p1.fun();
   p1 = Student();
   p1.fun();
   p1 = Soldier();
   p1.fun();
   return 0;
}
/*
全价票
全价票
全价票
*/

虚函数的重写

子类和父类中的虚函数拥有相同的名字,返回值,参数列表,那么称子类中的虚函数重写了父类的虚函数,或者叫做覆盖。

协变

子类的虚函数和父类的虚函数的返回值可以不同,也能构成重写。但需要子类的返回值是一个子类的指针或者引用,父类的返回值是一个父类的指针或者引用,且返回值代表的两个类也成继承关系。这个叫做协变。

class Person //人
{
  public:
  virtual Person* fun()
   {
       cout << "协变Person" << endl; 
       return nullptr;
   }
};
class Student : public Person 
{
   public:
   virtual Student* fun() 
   {
       cout << "协变Student" << endl;
       return nullptr;
   }
};

C++11 override && final

用final修饰的虚函数无法重写。用final修饰的类无法被继承。final像这个单词的意思一样,这就是最终的版本,不用再更新了。

被override修饰的虚函数,编译器会检查这个虚函数是否重写。如果没有重写,编译器会报错。

virtual void fun() final
{
    cout << "全价票" << endl; //成人票全价
}
virtual void fun() override
{
    cout << "全价票" << endl; //成人票全价
}

静态类型

对象定义时的类型,编译期间就确定好了

Base base;              //静态类型是Base
Derive derive;         //静态类型是Derive
Base* pbase; 
Base* pbase2 = new Derive();
Base* pbase3 = new Derive2();//以上三个静态类型是Base*

动态类型

对象目前所指的类型,运行时才决定的类型。一般来说,只有指针和引用才有动态类型的说法,而且一般指的是父类的指针或者引用。

pbase、derive、base没有动态类型

pbase2有动态类型,它的动态类型是Derive

pbase3有动态类型,它的动态类型是Derive2

动态类型在执行过程中可以改变

pbase = pbase2;//动态类型是Derive
pbase = pbase3;//动态类型是Derive2

总结:房子的类型是静态类型,房子里住的地址人对应的类型是动态类型

动态类型可以改变,因为子类可能不止一个