C++的虚函数与纯虚函数
C++项目看起来真的是太恼火了,源码阅读起来有点不便,幸亏有source insight 保命。C++有个很重要的特性,那就是多态。多态的实现主要是两种方式:一个就是函数的重载,另一个就是继承中对虚函数的重写。虚函数的引入对C++大型项目接口设计统一标准起到了非常重要的作用,与虚函数相对应的就是纯虚函数。
虚函数:用 virtual 标识标记的函数就是虚函数,只含有虚函数(且不含纯虚函数)的类就叫做虚类或者虚基类。虚函数必须要实现,可以是空函数体。被子类继承,子类不重写的话那就是直接基类的方法。
纯虚函数:同样含有 virtual 标识符,但是定义时函数则是在函数名后直接加 =0 定义;含有纯虚函数的类叫纯虚类,纯虚函数不用实现。子类只继承函数名,具体功能需要子类自己实现。
栗子奉上:
virtual void printTest(); //虚函数,需要函数体 virtual void printTest() = 0; //纯虚函数,只用定义
Java抽象类和接口
写过Java的人会发现,这个的功能特性与 java 的抽象类和接口的函数是类似的
抽象类:用 abstract 标识符标记的类就叫抽象类。抽象类的函数需要函数体,类似C++虚函数一样。
接口:与类(class)相对,用 Interface 标识符标记。接口只定义函数名,不具体实现。这个类似C++纯虚函数
直接栗子:
// 以下为多个文件 //-------------------- Base.java----------------- package test; abstract public class Base { // 基类,抽象类 public void printClass() { // 抽象类函数必须实现,不然会报错 System.out.println("print base class"); } } //------------------ Child1.java---------------- package test; public class Child1 extends Base{ // 子类继承,可直接继承基类函数,不用实现 } //------------------Child2.java---------------- package test; public class Child2 extends Base { @Override public void printClass() { // 子类继承,可对基类函数进行重写 System.out.println("print child2 class"); } } //**************************************************************************** //------------------------------ IBase.java------------------------- package test; public interface IBase { //接口,只定义接口函数形式,不具体实现 void printClass(); } //----------------------------- Child1_IBase.java---------------------- package test; public class Child1_IBase implements IBase { @Override public void printClass() { // 实现接口类,函数必须重写 System.out.println("print Interface Child1"); } } //*************************************************************************** //------------------TestMain.java-------------- package test; public class TestMain { public static void main(String[] args) { Child1 child1 = new Child1(); //未进行函数重写 Child2 child2 = new Child2(); //已进行函数重写 child1.printClass(); // 基类函数打印 child2.printClass(); // Child2 子类函数打印 Child1_IBase child1Interface = new Child1_IBase(); child1Interface.printClass(); } }
虚类和纯虚类 虚函数和纯虚函数
话说回C++,C++的虚函数和纯虚函数的实现也就跟这 java 抽象类和接口差不多了。栗子二连
#include <iostream> using namespace std; class base { //虚基类 public: virtual void printClass() { //虚函数实现 cout <<"print base class" <<endl; } }; class baseVirtual { //纯虚类,只要含有一个纯虚函数即是纯虚类 public: virtual void printClass() { //虚函数,需要实现 cout <<"print baseVirtual class" <<endl; } virtual void printClassVirtual() = 0; //纯虚函数,不需实现 }; //--------------------------------------------------------------- class sameChild1: public base { //子类继承,不自己重写虚函数 }; class overrideChild2: public base{ public: void printClass() override { // 虚函数重写,override 可不加上 cout <<"print child2 class" <<endl; } }; class virtualChild3 : public baseVirtual { public: void printClassVirtual() override { // 纯虚函数实现,override 可不加上 cout <<"print virtualChild3 class" <<endl; } }; //--------------------------------------------------------------- int main() { base baseIns; //虚基类,可以进行实例化 baseIns.printClass(); sameChild1 child1; // 子类,函数直接继承父类 child1.printClass(); overrideChild2 child2; // 子类,进行了函数重写 child2.printClass(); // baseVirtual baseVirIns; // 纯虚类,不可实例化 // baseVirIns.printClassVirtual(); virtualChild3 child3; // 纯虚类的子类,进行了纯虚函数的重写 child3.printClassVirtual(); return 0; }
结果输出:
与java不同之处:
1. java 的抽象类和接口都是不可以单独实例化的,只能由子类实例化
2. C++只有纯虚类不可以实例化,普通的虚基类可以进行实例化;因为方法有实现(但其实Java抽象类也有实现,哈哈哈)。
同时既然说到了 override,就说一下我的理解:
C++ override的使用
首先需要明确一个问题,那就是子类到底从基类中继承到了什么,这里只讨论函数方法
1. 基类中的纯虚函数,子类仅继承接口形式,具体函数体需要自己实现。
2. 基类中的虚函数,子类继承到了接口形式+缺省实现。具体函数一般还是要子类自己实现,当然也可直接使用基类的。
3. 基类中的非虚函数,子类继承到接口形式+具体实现。具体函数一般不需要子类自己实现,当然你强行想再实现也是可以的。
那就好像有没有 override 都可以正常实现虚函数的重写,那为什么要加个 override 呢?其实 override 是C++ 11之后加入的保留字,用于对虚函数重写的强制检查。举个栗子,还是上面那个示例,
class overrideChild2: public base{ public: /** * 函数名写错!!! * 假如没有 override ,程序员以为是对基类函数的重写,实际函数写错了。编译也不会有任何问题,到 * 函数调用的时候,仍然使用基类的接口形式调用;那么就会出现于预想中不一样的结果 **/ void printClassSSSP() /*override*/ { cout <<"print child2 class" <<endl; } };
对基类虚函数重写的错误,有可能因为函数名,参数类型,返回类型等等这些产生错误;但是这个是书写错误,这个是不容易查找出来的。派生类只会把这个当成是一个全新的函数,这是会带来很大的困扰,于是就有了 override 。被override 标识的函数,就明确表示是对基类函数的重写,那么必然需要有存在这样一个基类函数,在编译过程就会进行一个强制检查。如果发现基类中并没有这个函数,那说明是我们写错了函数,这样会保证虚函数的有效重写。所以 override 针对对象是基类的虚函数,非虚函数表示基类一般希望子类继承自己的方法实现,加上一个 override 同样也会报错提醒。
override 使用前提:
1)子类想改写基类函数;
2)基类函数为虚函数;
3)函数形式与基类保持一致(包括函数名,参数,返回类型)
说白了 override 就是一种辅助的措施,防止一些不必要的错误
ps: 还是写这些杂的轻松快乐。磕盐要加糖,我们都一样。
热门文章
- 2月3日 - 最高速度20.8M/S,2025年Nekobox每天更新免费节点订阅地址
- 使用Jenkins实现前端自动化打包部署(Linux版本)
- 由浅入深快速掌握Java 数组的使用_java
- 动物疫苗注射方法及部位 动物疫苗注射方法及部位图片
- 兰州哪里有卖狗粮的地方呀(兰州狗粮批发市场在哪)
- springboot整合SpringSecurity实现认证、授权功能简单入门案例
- 1月6日 - 最高速度19.6M/S,2025年Nekobox每天更新免费节点订阅地址
- 买一个宠物狗粮食(买一点普通的狗粮多少钱一斤)
- MySQL的安装和配置(超详细图文教程)
- 动物疫苗生产企业排行榜最新名单图片(动物疫苗行业龙头)