【C++基础】--多态
深入了解多态
- 一、认识多态
- 二、定义及实现
- 构成条件
- 虚函数重写
- C++11 override 和 final
- final:修饰虚函数,表示该虚函数不能再被重写
- override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
- 三、抽象类
- 概念
- 四、多态的实现原理
- 扩展
一、认识多态
多态作为面向对象三大特征之一,指的是一个接口可以有多个不同的实现方式。简单说,就是同一个函数或方法调用,可以根据上下文的不同执行不同的功能。在C++中,多态主要是通过基类的指针或引用,来调用子类的重写函数实现。C++中的多态主要是通过虚函数来实现。
示例:
#include <iostream>
using namespace std;class Base {
public:virtual void show() {cout << "Base class show function" << endl;}
};class Derived : public Base {
public:void show() override {cout << "Derived class show function" << endl;}
};int main() {Base* basePtr;Derived derivedObj;basePtr = &derivedObj;basePtr->show(); // 输出:Derived class show functionreturn 0;
}
在上述代码中,通过基类指针basePtr,调用子类derivedObj的show方法。这就是多态。
二、定义及实现
构成条件
在继承中构成多态满足以下条件:
1.必须通过基类的指针或者引用调用虚函数
2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
虚函数重写
虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-半价" << endl; }
/*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用*/
/*void BuyTicket() { cout << "买票-半价" << endl; }*/
};
void Func(Person& p)
{ p.BuyTicket(); }
int main()
{Person ps;Student st;Func(ps);Func(st);return 0;}
C++11 override 和 final
final:修饰虚函数,表示该虚函数不能再被重写
class Car
{
public:virtual void Drive() final {}
};
class Benz :public Car
{
public:virtual void Drive() {cout << "Benz-舒适" << endl;}
};
override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
class Car{
public:virtual void Drive(){}
};
class Benz :public Car {
public:virtual void Drive() override {cout << "Benz-舒适" << endl;}
};
三、抽象类
概念
在虚函数的后面写上=0,则这个虚函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫做接口),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对对象。纯虚函数规范了派生类重写,另外纯虚函数更体现了接口继承。
class Car
{
public:virtual void Drive() = 0;
};
class Benz :public Car
{
public:virtual void Drive(){cout << "Benz-舒适" << endl;}
};
class BMW :public Car
{
public:virtual void Drive(){cout << "BMW-操控" << endl;}
};
void Test()
{Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();
}
四、多态的实现原理
多态的实现原理,主要是虚函数、虚函数表和虚函数指针方向。
多态通过虚函数实现。通过虚函数,子类可以重写父类的方法,当通过基类指针或引用调用时,会根据对象的实际类型调用对应的函数实现。
更深层次的原理,是通过虚表(vtable)和虚表指针(vptr)机制实现的。虚表是一个函数指针数组,包含了该类的所有虚函数的地址,而虚表指针存储在对象实例中,指向属于该对象的虚表。
扩展
- 虚函数和重写:在基类中使用关键字virtual声明虚函数后,在子类中可以重写这个函数
- 虚表(vtable):每个包含虚函数的类都会有一个虚表(vtable),这个虚表在编译时生成。他包含该类所有虚函数的指针。对于每个类(而不是每个对象),编译器会创建一个唯一的虚表。
- 虚表指针(vptr):每个包含虚函数的对象实例会有一个隐藏的虚表指针(vptr),他在对象创建时自动初始化,指向该类的虚表。不同类型的对象,其虚表指针会指向不同的虚表。例如
- 多态的调用机制:当通过基类指针或引用调用虚函数时,程序会通过该类指针或引用找到对应的对象,然后通过虚表指针找到正确的虚表中的函数地址,最终调用适当的函数实现,这样程序能够在运行时决定调用哪一个函数实现。
实例:
class Base {
public:virtual void show() {std::cout << "Base show" << std::endl;}
};class Derived : public Base {
public:void show() override {std::cout << "Derived show" << std::endl;}
};void demonstratePolymorphism(Base &obj) {obj.show(); // 依赖于实际对象的类型
}int main() {Base b;Derived d;demonstratePolymorphism(b); // 输出 "Base show"demonstratePolymorphism(d); // 输出 "Derived show"return 0;
}