virtual

C++中的virtual关键字主要有这样几种使用场景:第一,修饰父类中的函数 ;第二,修饰继承性。注意:友元函数、构造函数、static静态函数不能用virtual关键字修饰。普通成员函数和析构函数可以用virtual关键字修饰。

virtual具有继承性:父类中定义为virtual的函数在子类中重写的函数也自动成为虚函数。

一定要注意: 只有子类的虚函数和父类的虚函数定义完全一样才被认为是虚函数,比如父类后面加了const,如果子类不加的话就是隐藏了,不是覆盖.

修饰父类中的函数

修饰父类中的函数主要分为三种:普通函数、析构函数和纯虚函数。

修饰父类中的普通函数

被修饰的函数称为虚函数, 是C++中多态的一种实现(多说一句,多态分编译时多态-通过重载实现和运行时多态-通过虚函数实现)。 也就是说用父类的指针或者引用指向其派生类的对象,当使用指针或引用调用函数的时候会根据具体的对象类型调用对应对象的函数(需要两个条件:父类的函数用virtual修饰和子类要重写父类的函数)。下面用一个例子来说明:

#include <iostream>class father {public:void func1() {std::cout << "this is father func1" << std::endl;}virtual void func2() {std::cout << "this is father func2" << std::endl;
}class son:public father {public:void func1() {std::cout << "this is son func1" << std::endl;}void func2() {std::cout << "this is son func2" << std::endl;
}int main() {father *f1 = new son();f1.func1();f1.func2();return 0;
}

output:

this is father func1
this is son func2

通过上面的例子可以看出,使用virtual修饰的函数会根据实际对象的类型来调用,没有使用virtual修饰的根据指针的类型来调用。虚函数最关键的特点是“动态联编”,它可以在运行时判断指针指向的对象,并自动调用相应的函数。

修饰析构函数

修饰析构函数与上面讲到的使用方法和原理相同,虚析构函数在销毁时会调用对象的析构函数,这样就不会出现像有的数据成员没有销毁导致内存泄露的问题或者程序直接崩溃。下面也用一个例子说明:

class GrandFather {public:GrandFather() {std::cout << "construct grandfather" << std::endl;}~GrandFather() {std::cout << "destruct grandfather" << std::endl;}
};class Father:public GrandFather{public:Father() {std::cout << "construct father" << std::endl;}~Father() {std::cout << "destruct father" << std::endl;}
};class Son:public Father{public:Son() {std::cout << "construct son" << std::endl;}~Son() {std::cout << "destruct son" << std::endl;}
};int main() {Father *f = new Son();delete f;return 0;
}

output:

construct grandfather
construct father
construct son
destruct father
destruct grandfather

我们发现没有调用son的析构函数,当将Father或者GrandFather其中一个的析构函数修改为virtual后输出就变为了

construct grandfather
construct father
construct son
destruct son
destruct father
destruct grandfather

纯虚函数

纯虚函数的定义是在虚函数的后面加一个=0。定义了纯虚函数的类是一个抽象类。

virtual void func() = 0;

纯虚函数需要注意这几点:
1.定义了纯虚函数的类不能够实例化,也就是不能够创建对象
2.继承了含有纯虚函数的父类的子类如果没有实现纯虚函数也不能够实例化

修饰继承性

假如有这种场景,一个类继承两个或者更多的父类,但是这些父类里又有一些有共同的父类,会出现什么情况呢?

class GrandFather {public:GrandFather() {std::cout << "construct grandfather" << std::endl;}~GrandFather() {std::cout << "destruct grandfather" << std::endl;}
};class Father1:public GrandFather{public:Father1() {std::cout << "construct father1" << std::endl;}~Father1() {std::cout << "destruct father1" << std::endl;}
};class Father2:public GrandFather{public:Father2() {std::cout << "construct father2" << std::endl;}~Father2() {std::cout << "destruct father2" << std::endl;}
};class Son:public Father1, Father2{public:Son() {std::cout << "construct son" << std::endl;}~Son() {std::cout << "destruct son" << std::endl;}
};int main() {Father *f = new Son();delete f;return 0;
}

output:

construct grandfather
construct father1
construct grandfather
construct father2
construct son
destruct son
destruct father2
destruct grandfather
destruct father1
destruct grandfather

通过这个例子我们看到创建一个son会创建两个grandfather,不符合我们的预期啊,而且还可能会导致程序挂掉。这里就请virtual出场了,当把father1和father2继承grandfather修改为virtual继承(也就是在public前面加一个virtual)的时候输出会变成这样:
output:

construct grandfather
construct father1
construct father2
construct son
destruct son
destruct father2
destruct father1
destruct grandfather

这比较符合我们的预期。

C++基础之关键字——virtual详解相关推荐

  1. C++ Virtual详解

    C++ Virtual详解 Virtual是C++ OO机制中很重要的一个关键字.只要是学过C++的人都知道在类Base中加了Virtual关键字的函数就是虚拟函数(例如函数print),于是在Bas ...

  2. linux下mysql数据库基础及客户端命令详解

    linux下mysql数据库基础及客户端命令详解 1.mysql数据库存储引擎: SHOW ENGINES;   #查看mysql支持的存储引擎 常见有如下两个存储引擎: MyISAM:每表三个文件: ...

  3. mysql常见关键字的用法_MySQL 常用关键字用法详解

    MySQL 常用关键字用法详解 在开发工程中,操作数据库的时候经常会有不同类型的条件查询,除了使用where外,Mysql本身也提供了很多常用的关键字.本文主要介绍一些常用的关键字,像update.i ...

  4. C++中const关键字用法详解及实例和源码下载(一)

    最近在学习C++基础部分,看了两天书,已经看过了一遍,半知半解,回过头来重新看第二遍,深入了解一下C++的基础知识.现在读到了const关键字的用法,书上面讲解的时候并没有给出完整的实例,只是理论的讲 ...

  5. 2014计算机应用基础试题及答案,2014年计算机应用基础试题及答案详解.doc

    2014年计算机应用基础试题及答案详解.doc 计算机应用基础2资料 一.单选题 1.第一台电子计算机是1946年在美国研制成功的,该机的英文缩写名是______.答案: A A:ENIAC B:ED ...

  6. C++-[override]关键字使用详解

    本文介绍了C++ override关键字使用详解以及与重载的区别. C++ override关键字使用详解 一.override作用 二.override在基类与派生类的应用 2.1. 纯虚函数 2. ...

  7. Android基础总结: Camera2详解之一 API学习

    Camera2的API出来有些年头了,只是赶项目多次使用,没时间好好总结,年终了,正好结合google的官方Camera2demo 和开发中使用的情况,做个详细梳理,研究总结之后,才发现Camera2 ...

  8. LSTM入门必读:从入门基础到工作方式详解 By 机器之心2017年7月24日 12:57 长短期记忆(LSTM)是一种非常重要的神经网络技术,其在语音识别和自然语言处理等许多领域都得到了广泛的应用

    LSTM入门必读:从入门基础到工作方式详解 By 机器之心2017年7月24日 12:57 长短期记忆(LSTM)是一种非常重要的神经网络技术,其在语音识别和自然语言处理等许多领域都得到了广泛的应用. ...

  9. 【Java基础】HashMap原理详解

    [Java基础]HashMap原理详解 HashMap的实现 1. 数组 2.线性链表 3.红黑树 3.1概述 3.2性质 4.HashMap扩容死锁 5. BATJ一线大厂技术栈 HashMap的实 ...

最新文章

  1. 大天使之剑服务器维护,大天使之剑————【维护】10月20日更新维护公告
  2. 跨链Cosmos(5)ABCI 接口
  3. 【收藏】Maven 生成打包可执行jar包
  4. c语言实现循环单链表
  5. 安装 elasticsearch-head
  6. UTF-8编码规则(转)
  7. axis2 json_带有Java和Axis2的JSON Web服务
  8. 织梦熊掌号提交urls.php,织梦熊掌号api自动提交代码
  9. linux+镜像命令在哪里,怎么查看 linux 镜像文件
  10. redhat装java_redhat下安装java
  11. 实验——示波器法测量相位差(试验记录)
  12. Ajax请求回调函数没有被调用
  13. 电路里的希腊字母读音
  14. java驱动打印机,r230打印机驱动-r230打印机驱动 免费版
  15. 计算机储存容量5mb,笔记本电脑的硬盘上 8455MB(CYL 16383,H16,S63) 640GB (LBA 1,250,263,728Sectors) 分别表示什么意思?...
  16. 橘子与萝卜同食容易导致甲状腺肿(图)
  17. golang的ECB加密代码文件下载
  18. C++:应用有限差分法求解 稳平流扩散方程 v*ux-k*uxx=0 in 一个空间维度,具有恒定的速度 v 和扩散系数 k(附完整源码)
  19. 移动端js判断iPhone浏览器还是Android浏览器
  20. DST ROOT CA X3过期,浏览器https——您的连接不是私密连接

热门文章

  1. 遇到跑批时快时慢、或一直变慢,作为运维DBA或开发的你,如何下手?
  2. [CSS]CSS 的背景
  3. protel99se封装库中的三个文件夹说明
  4. mysql 获取倒数第二_MySQL查询倒数第二条记录实现方法
  5. HTML怎么设置下划线及去掉下划线
  6. FR607-ASEMI快恢复二极管FR607
  7. Teamface可定制化的CRM管理软件,颠覆传统的管理软件
  8. Java回调函数异步回调案例
  9. dbeaver——sql编辑区字体设置@baiyun
  10. 占地2000亩!这所985高校国际校区开建