多态:不同对象去调同一个函数会有不一样的行为。
多态必须满足两个条件:
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;
}
多继承就会有多个虚表。