2026/1/8 8:55:47
网站建设
项目流程
嘉兴做网站设计,深圳设计馆,wordpress表格插件,wordpress主题在那个目录C面向对象的三大特性是封装#xff0c;继承#xff0c;多态。上两篇文章分别讨论了封装和继承#xff0c;今天主要是讲解C的另一个面向对象的特性~~多态
多态的概念
什么是多态呢?
多态的核心是同一个接口#xff0c;不同的实现
简单来说#xff0c;就是调用…C面向对象的三大特性是封装继承多态。上两篇文章分别讨论了封装和继承今天主要是讲解C的另一个面向对象的特性~~多态多态的概念什么是多态呢?多态的核心是同一个接口不同的实现简单来说就是调用同一个函数名程序会根据上下文和调用对象的实际类型来自动执行对应的函数逻辑后面我们将会用代码来举例说明多态的分类C多态分为静态多态和动态多态静态多态静态多态是编译时多态编译器在编译阶段就确定要调用的函数版本主要通过函数重载、模板实现用代码举例如下:#includeiostreamusingnamespacestd;// 重载1计算两个整数的和intadd(intaintb){returnab;}// 重载2计算三个浮点数的和doubleadd(doubleadoublebdoublec){returnabc;}intmain(){coutadd(12)endl;// 调用int版本输出3coutadd(1.12.23.3)endl;// 调用double版本输出6.6return0;}这里编译器根据参数的个数、类型在编译时就确定了要调用的add()函数动态多态动态多态是运行时多态程序在运行阶段才确定要调用的函数版本动态多态的实现需要以下三个条件存在继承关系父类声明虚函数子类重写该虚函数使用父类的指针指向子类对象由于还没有说到虚函数暂时先不用代码举例等说完虚函数再一并举例虚函数上面说到虚函数是动态多态实现的必要条件之一那么什么是虚函数呢?普通虚函数虚函数是在父类中用virtual关键字修饰的成员函数调用时要根据对象的实际类型来动态绑定而不是编译时固定绑定// 父类图形classShape{public:// 虚函数绘制图形virtualvoiddraw(){cout绘制基础图形endl;}doublegetArea(){return1;}};上述代码中用virtual关键字修饰的draw()函数就是虚函数调用时要根据对象的实际类型来决定其内容假如它的子类如下所示:// 子类圆形classCircle:publicShape{private:doubleradius;public:Circle(doubler):radius(r){}// 重写父类的虚函数override关键字可选但建议加voiddraw()override{cout绘制半径为radius的圆形endl;}doublegetArea(){returnM_PI*radius*radius;}};上述代码中子类Circle的成员函数draw()有关键字override来修饰是对父类虚函数draw()的重写假如调用情况如下所示:intmain(){// 父类指针指向子类对象多态的关键Shape*shapenewCircle(5.0);// 调用的是子类Circle的draw和getArea动态绑定shape-draw();// 输出绘制半径为5的圆形cout面积shape-getArea()endl;// 输出面积78.5398deleteshape;return0;}由于实际的对象由Shape* shape new Circle(5.0);决定所以draw()函数是执行Circle类的内容而不是父类Shape的内容这就是虚函数的内容也是动态多态的内容(满足动态多态的三个条件)虚函数的实现原理我们已经知道了虚函数的用法那么虚函数是怎么实现动态多态的呢?下面我们简单了解其原理编译器为了实现虚函数的动态绑定做了两件事:分别是创建虚函数表和添加虚表指针虚函数表是每个包含虚函数的类(包括父类和子类)都会有一个独立的虚函数表表中存储了该类所有虚函数的地址。上述代码中Shape类和Circle类都有各自的虚函数表表中存储虚函数draw()的地址虚表指针是每个对象会包含一个隐藏的虚表指针指向所属类的虚函数表。上述代码Shape* shape new Circle(5.0);中的对象shape存在一个虚函数指针指向Circle类里的虚函数表里的draw()的地址当程序运行时通过对象的虚表指针找到对应的虚函数表再调用表中的函数地址从而实现 “根据对象实际类型调用函数”纯虚函数上述虚函数的例子是有实际意义的有时候父类的虚函数没有实现意义这时可以定义纯虚函数格式是在函数后加 0classShape{public:// 纯虚函数没有函数体强制子类必须重写virtualdoublegetArea()0;// 普通虚函数可以有默认实现virtualvoiddraw(){std::cout绘制基础图形std::endl;}virtual~Shape(){}};包含纯虚函数的类称为抽象类不能实例化对象只能作为基类被继承同时子类必须重写所有纯虚函数虚析构函数当类中有虚函数时必须将析构函数声明为虚函数否则会导致内存泄漏代码如下:#includeiostream#includecmathusingnamespacestd;classShape{public:// 1. 业务虚函数多态的核心接口virtualvoiddraw()0;// 纯虚函数强制子类实现virtualdoublegetArea()0;// 2. 虚析构函数配合多态删除场景必须加virtual~Shape(){coutShape析构endl;}};classCircle:publicShape{private:doubleradius;public:Circle(doubler):radius(r){}// 重写业务虚函数voiddraw()override{cout绘制圆形半径radiusendl;}doublegetArea()override{returnM_PI*radius*radius;}~Circle()override{coutCircle析构endl;}};intmain(){// 多态场景父类指针指向子类对象Shape*shapenewCircle(5.0);shape-draw();// 调用子类的draw业务虚函数的作用deleteshape;// 调用子类的析构虚析构函数的作用return0;}上述代码中由于Shape类和Circle类都有虚函数所以必须要有虚析构函数避免内存泄漏如果想更深入了解虚析构函数可以看我往期关于虚析构函数的文章那里有更具体的描述~总结本文通过动态的概念、分类、虚函数、纯虚函数、虚析构函数这几个方面来描述了C面向对象之多态的内容并通过具体代码示例来深入分析多态的实现原理和演示多态的实现过程本文暂时写到这里如果文章对你有用的话欢迎点赞收藏~感兴趣的话也可以关注我我会持续输出C相关的内容~