多态
不同的对象可以使用同一个函数名调用不同内容的函数
静态多态性:在程序编译时系统就决定调用哪个函数,比如函数重载
动态多态性:在程序运行过程中动态确定调用那个函数,通过虚函数实现的。
虚函数
声明
virtual 函数类型 函数名 (参数列表);
特点
可以使用基类对象指针访问派生对象的同名函数
将基类中的函数声明为虚函数,派生类中的同名函数自动为虚函数。
构造函数不能声明为虚函数,析构函数可以声明为虚函数。
vfptr和vftable
虚函数会产生一个虚函数指针(vfptr)和虚函数表(vftable),vfptr指向哪里要看是否发生继承
1.不发生继承
class Animal { public: virtual void sleep(){ cout<<"animal"<<endl; } };
深入研究
vfptr虚函数指针,指向的是虚函数表(vftable)
vftable表存放的是虚函数的入口地址,
不发生继承时,虚函数表中存放的是自身的虚函数地址
一旦涉及继承,虚函数指针和虚函数表都会被继承,但是虚函数中的入口地址改成了子类的虚函数
2.如果发生继承
class Animal { public: virtual void sleep(){ cout<<"animal"<<endl; } }; class Cat:public Animal { public: void sleep(){ cout<<"cat"<<endl; } };
深入分析
通过修改虚函数表中的虚函数入口地址,完成指向操作。
总结
总结:当虚函数涉及到继承的时候子类会继承父类的(虚函数指针vfptr和虚函数表vftable),编译器会将虚函数表中的函数入口地址更新成子类的同名(返回值、参数都相同)的函数入口地址。
如果基类指针、引用访问虚函数的时候就会间接的调用子类的虚函数.
纯虚函数
在基类中不执行具体的操作,只为派生类提供统一结构的虚函数,将其声明为虚函数。
声明
virtual 函数类型 函数名(参数表) = 0;
例
#include <iostream>
using namespace std;
// 抽象基类
class Shape {
public:
// 纯虚函数,需要在派生类中实现
virtual double getArea() const = 0;
};
// 派生类
class Rectangle : public Shape {
private:
double width;
double height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double getArea() const override {
return width * height;
}
};
// 派生类
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double getArea() const override {
return 3.14 * radius * radius;
}
};
int main() {
Shape* shape1 = new Rectangle(5, 7);
Shape* shape2 = new Circle(3);
cout << "Rectangle area is: " << shape1->getArea() << endl;
cout << "Circle area is: " << shape2->getArea() << endl;
delete shape1;
delete shape2;
return 0;
}