C++ 多态

发布于:2025-05-26 ⋅ 阅读:(72) ⋅ 点赞:(0)

多态:不同对象去调同一个函数会有不一样的行为。

多态必须满足两个条件:

1.父子类完成虚函数的重写

2.父类的指针或者引用调用虚函数。

虚函数:类成员函数前⾯加virtual修饰。

虚函数的重写/覆盖:派⽣类中有⼀个跟基类完全相同的虚函数(即派⽣类虚函数与基类虚函数的返回值 类型、函数名字、参数列表完全相同),称派⽣类的虚函数重写了基类的虚函数。

class Person {
 public:
 virtual void BuyTicket() { cout << "买票全价" << endl; }
 };

class Student : public Person {
 public:
 virtual void BuyTicket() { cout << "买票打折" << endl; }
 };

void Func(Person* ptr)
 {
 
    ptr->BuyTicket();
 }

 int main()
 {
     Person ps;
     Student st;
     Func(&ps);
     Func(&st);
     return 0;
 }

析构函数的重写:(基类与子类的函数名不同)

基类的析构函数为虚函数,此时派⽣类析构函数只要定义,⽆论是否加virtual关键字,都与基类的析 构函数构成重写。

 class A
 {
 public:
 virtual ~A()
 {
 cout << "~A()" << endl;
 }
 };

 class B : public A {
 public:
 ~B()
 { 
cout << "~B()->delete:"<<_p<< endl;
 delete _p;
 }
 protected:
 int* _p = new int[10];
 };


int main()
 {
 A* p1 = new A;
 A* p2 = new B;
 delete p1;
 delete p2;
 return 0;
}

//为什么基类中的析构函数建议设计为虚函数。
//如果A析构函数不加virtual,不构成多态,就会存在B的内存泄漏(前提是继承)
 class A
 {
 public:
 virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;}
 virtual void test(){ func();}// A*this       this调用func
 };

 class B : public A
 {
 public:
 void func(int val = 0){ std::cout<<"B->"<< val <<std::endl; }
 };
 int main(int argc ,char* argv[])
 {
 B*p = new B;
 p->test();//调用test是 A*this 
 return 0;
 }

//上面的func构成重写(三同)
//构成多态:因为test就是父类的指针
//指向谁


//虚函数的重写的是函数体的实现
//函数结构部分(函数名,参数,返回值)用的是父类的
结果是B->1



final修饰的类叫做最终类,不能继承。例如

class Car final
 {
 public:
 virtual void Drive() = 0;
 };
 class Benz :public Car    //error
 {
 public:
 virtual void Drive()
 {
 cout << "Benz 舒适" << endl;
 }
 };

override,可以帮助⽤⼾检测是否重写。如果我们不想让派⽣类重写这个虚函数,那么可以⽤final去修饰。

class Car {
 public:
 virtual void Dirve()
 {}
 };
 class Benz :public Car {
 public:
 virtual void Drive() override { cout << "Benz 舒适" << endl; }//override检查重写,没有重写会报错
 };
class Car
 {
 public:
 virtual void Drive() final {}//不能重写
 };
 class Benz :public Car
 {
 public:
 virtual void Drive() {};
 };

重载/重写/隐藏的对比: 

 虚函数表指针(虚表指针):只要有虚函数就有虚表指针。

虚函数和普通函数一样,都是存在代码段,不是存在虚表中的。

需表中存的是虚函数的地址。

虚表存在常量区。

多态的实现:满足多态后,运行时,调用生成的指令,即就会去指向对象的虚表中找对应的虚函数进行调用,指向谁就调用谁。

在虚函数的后⾯写上=0,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义因为要被 派⽣类重写,但是语法上可以实现),只要声明即可。

包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象。

//抽象类 
//间接强制派生类重写虚函数
class Car
 {
 public:
 virtual void Drive() = 0;//纯虚函数
 };

 class Benz :public Car  //也是抽象类,因为继承了Car
 {
 public:
 virtual void Drive()
 {
 cout << "Benz 舒适" << endl;
 }
 };

int main()
{
    Car car;//error,因为是抽象类,不能实例化。

    Benz  b1;//ok的

    Car* pBenz = new Benz;
    pBenz->Drive();
    return 0;
}

多继承就会有多个虚表。