C++之多态
一、什么是多态
-
指的是一条指令可以有多种形态,当调用一个指令时,它能够根据参数、环境的不同作出不同的操作,这种情况称为多态
-
C++中根据确定指令具体操作的时间划分多态:
编译时多态、运行时多态
二、两种多态
-
编译时多态:
当调用函数重载版本时,编译器会根据参数的类型、个数等确定调用的是哪个版本的重载函数,这就是所谓的编译时多态,还有例如泛型编程中模版技术等 -
运行时多态:
当子类覆盖了父类的同名函数,然后使用父类指针或引用去访问虚函数,该父类指针或引用既可能指向父类对象、也可能指向子类对象,所以调用的是父类还是子类的同名函数在编译期间无法确定,需要在运行期间才能确定,称为运行时多态(必须发生覆盖) -
构成 运行时多态 的条件:
- 父子类以public继承
- 子类中有对父类成员函数构成覆盖
- 运行时才能确定父类指针或引用指向的是父类还是子类的对象
三、虚构造和虚析构
-
虚构造:
C++ 中不允许构造函数为虚函数
假设构造函数可以定义为虚函数,那么此时子类的构造函数就会自动覆盖父类的构造函数,当创建子类对象时,会执行子类的构造函数,但是按照执行顺序会先执行父类的构造函数,而此时父类的构造函数已经被覆盖成子类的构造函数,又重新回来形成死循环,所以编译器禁止把构造函数定义为虚函数
其次构造函数的使命就是去把类中的成员创建,包括虚函数表、虚表指针,因此如果把构造函数定义为虚函数,但是构造函数都没有执行成功就没有所谓的虚函数表、虚表指针,因此想要把构造函数放入虚函数表中就是一个悖论 -
虚析构:
析构函数可以定义为虚函数
当使用类多态,通过父类指针或引用释放子类对象时,如果析构函数不是虚函数,那么只会执行父类的析构函数,但是由于在创建子类对象时,一定执行了子类的构造函数,如果在子类构造函数中申请了资源,此时对象销毁时没有调用子类的析构函数,就会导致内存泄漏
只有把父类的析构函数定义为虚函数,通过父类指针或引用释放子类对象时,会先调用子类的析构函数(覆盖),当子类的析构函数执行结束后,按照对象的释放顺序,会自动执行父类的析构函数,此时子类已经被释放完,所以调用父类的析构函数不会再继续因为覆盖而去执行子类的析构函数,因此不会造成内存泄漏 -
总结:
当使用多态时且子类的析构函数中有需要释放的资源,此时父类中就必须设置为虚析构
四、纯虚函数、抽象类、纯抽象类
-
纯虚函数的格式
virtual 返回值 函数名(参数列表) = 0;
-
纯虚函数可以不去实现,一般人也没必要去实现
-
父类中如果有纯虚函数,那么继承该父类的子类必须对其进行覆盖,否则无法创建对象
-
有纯虚函数的类不能创建对象
-
纯虚函数就是为了强制子类去覆盖他,为了强制实现某些功能
-
有纯虚函数的类都称为抽象类
-
析构函数可以设置为纯虚函数,但是必须定义在类外定义
-
-
纯抽象类
所有的成员函数都是纯虚函数的类,称为纯抽象类,这种类一般用于设置功能接口,所以也称为接口类 -
了解一下工厂模式,实现一个简单的工厂模式
#include <iostream> using namespace std; enum Phone { C_Huawei,C_Xiaomi,C_Apple,C_Oppo }; class Factory { public: virtual void makephone(void) = 0; }; class Huawei : public Factory { public: void makephone(void) { cout << "华为手机" << endl; } }; class Xiaomi : public Factory { public: void makephone(void) { cout << "小米手机" << endl; } }; class Apple : public Factory { public: void makephone(void) { cout << "苹果手机" << endl; } }; class Oppo : public Factory { public: void makephone(void) { cout << "欧泊手机" << endl; } }; Factory* create_phone(Phone phone) { switch(phone) { case C_Huawei: return new Huawei; case C_Xiaomi: return new Xiaomi; case C_Apple: return new Apple; case C_Oppo: return new Oppo; } } int main(int argc,const char* argv[]) { Factory* phone = create_phone(C_Xiaomi); phone->makephone(); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!