轻松搞定面试中的“虚"
提要
今天要整理的知识点是C++中有关虚的一切。
包括:虚函数,纯虚函数,虚基类,虚继承...
1.什么是虚函数,有什么作用?
在基类用virtual声明成员函数为虚函数。这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便地被调用。在类外定义虚函数时,不必再加virtual。该函数就是虚函数了。虚函数是多态性的基础,其调用的方式是动态联编(程序运行时才决定调用基类的还是子类)。虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数,达到多态的目的。
2.什么是纯虚函数,什么是纯虚类,有什么作用?
纯虚函数只有函数的名字而不具备函数的功能,不能被调用。它只是通知编译系统:“在这里声明一个虚函数,留待派生类中定义”。在派生类中对此函数提供定义后,它才能具备函数的功能,可被调用。声明纯虚函数的一般形式是
virtual 函数类型 函数名 (参数表列)=0;
纯虚类也称抽象类,凡是包含纯虚函数的类都是抽象类。因为纯虚函数是不能被调用的,包含纯虚函数的类是无法建立对象的。
抽象类的作用是作为一个类族的共同基类,或者说,为一个类族提供一个公共接口。
3.为什么有的类的析构函数需要设为virtual?是否每个类的析构函数都要设置成virtual?是否可以将析构函数设置成内联函数。
这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。
可以。
4.析构函数是否可以是纯虚函数?
可以,当需要定义一个抽象类,如果其中没有其他合适的函数,可以把析构函数定义为纯虚的。
5.是否可以将构造函数声明为virtual?
虚函数的意思就是开启动态绑定,程序会根据对象的动态类型来选择要调用的方法。然而在构造函数运行的时候,这个对象的动态类型还不完整,没有办法确定它到底是什么类型,故构造函数不能动态绑定。(动态绑定是根据对象的动态类型而不是函数名,在调用构造函数之前,这个对象根本就不存在,它怎么动态绑定?)
6.是否可以在析构函数或者构造函数中调用虚函数?
在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。
在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。
7.什么叫虚继承?有什么作用?
虚继承,就是在被继承的类前面加上virtual关键字,这时被继承的类称为虚基类。虚继承在多重继承的时可以防止二义性。主要用在如下的菱形继承:
- class A
- class B1:public virtual A;
- class B2:public virtual A;
- class D:public B1,public B2;
由于共享所以不必要在对象内存中保存多份虚基类子对象的拷贝,这样较之多继承节省空间。虚拟继承与普通继承不同的是,虚拟继承可以防止出现diamond继承时,一个派生类中同时出现了两个基类的子对象。也就是说,为了保证这一点,在虚拟继承情况下,基类子对象的布局是不同于普通继承的。因此,它需要多出一个指向基类子对象的指针。
8.什么是虚函数表?
为实现动态联编,编译器为每个包含虚函数的类创建一个表,称为vtable,在vtable中,编译器放置了特定类的虚函数地址,在每个带有虚函数的类中编译器会秘密地设置一个虚函数表指针,称为vptr,指向对象的vtable,通过基类指针做虚函数调用时,也就是多态调用时,编译器静态地插入取得这个vptr,并在vtable表种查找函数地址的代码,这样就能调用正确的函数。
9.什么是动态联编?
动态联编是指在程序执行的时候才将函数实现和函数调用关联,因此也叫运行时绑定或者晚绑定,动态联编对函数的选择不是基于指针或者引用,而是基于对象类型,不同的对象类型将做出不同的编译结果。C++中一般情况下联编也是静态联编,但是一旦涉及到多态和虚拟函数就必须要使用动态联编了。
10.什么是RTTI?
RTTI(Run-Time Type Information)运行时类型检查的英文缩写,它提供了运行时确定对象类型的方法,通过RTTI,能够通过基类的指针或引用来检索其所指对象的实际类型。c++通过下面两个操作符提供RTTI:
(1)typeid:返回指针或引用所指对象的实际类型。
(2)dynamic_cast:将基类类型的指针或引用安全的转换为派生类型的指针或引用。
对于带虚函数的类,在运行时执行RTTI操作符,返回动态类型信息;对于其他类型,在编译时执行RTTI,返回静态类型信息。
轻松搞定面试中的“虚"的更多相关文章
- 剑指XX游戏(六) - 轻松搞定面试中的红黑树问题
原文地址 http://blog.csdn.net/silangquan/article/details/18655795?utm_source=tuicool&utm_medium=refe ...
- 轻松搞定面试中的二叉树题目(java&python)
树是一种比较重要的数据结构,尤其是二叉树.二叉树是一种特殊的树,在二叉树中每个节点最多有两个子节点,一般称为左子节点和右子节点(或左孩子和右孩子),并且二叉树的子树有左右之分,其次序不能任意颠倒.二叉 ...
- 面试大总结:Java搞定面试中的链表题目总结
package LinkedListSummary; import java.util.HashMap; import java.util.Stack; /** * http://blog.csdn. ...
- 面试大总结之二:Java搞定面试中的二叉树题目
package BinaryTreeSummary; import java.util.ArrayList; import java.util.Iterator; import java.util.L ...
- (转)面试大总结之一:Java搞定面试中的链表题目
面试大总结之一:Java搞定面试中的链表题目 分类: Algorithm Interview2013-11-16 05:53 11628人阅读 评论(40) 收藏 举报 链表是面试中常出现的一类题目, ...
- Java原来还可以这么学:如何搞定面试中必考的集合类
原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 系列文章介绍 本文是<五分钟学Java>系列文章的一篇 本系列文章主要围绕Java程序员必须掌握的核心技能,结合我个人三年 ...
- 三步轻松搞定delphi中CXGRID手动添加复表头(多行表头,报表头)
网上有代码动态生成cxgrid多行表头的源码,地址为:http://mycreature.blog.163.com/blog/static/556317200772524226400/ 如果要手动设计 ...
- 一篇文章搞定面试中的链表题目(java实现)
最近总结了一下数据结构和算法的题目,这是第二篇文章,关于链表的,第一篇文章关于二叉树的参见 废话少说,上链表的数据结构 class ListNode { ListNode next; int val; ...
- 一篇文章搞定面试中的二叉树题目(java实现)
最近总结了一些数据结构和算法相关的题目,这是第一篇文章,关于二叉树的. 先上二叉树的数据结构: class TreeNode{ int val; //左孩子 TreeNode left; //右孩子 ...
随机推荐
- Search for a Range leetcode java
题目: Given a sorted array of integers, find the starting and ending position of a given target value. ...
- Restful安全认证及权限的解决方案
一.Restful安全认证常用方式 1.Session+Cookie 传统的Web认证方式.需要解决会话共享及跨域请求的问题. 2.JWT JSON Web Token. 3.OAuth 支持两方和三 ...
- socket bind 随机端口
https://www.cprogramming.com/code_blocks/ 这个地址可以下载c, c++的编译器,在windows下可以用的 IDE. bind到端口0上,系统就会自动分配,但 ...
- c语言基础,\r, \n, \r\n
Enumeration (or enum) in C Enumeration (or enum) is a user defined data type in C. It is mainly used ...
- Linux学习笔记之初级篇
第一部分:[安装注意环节] 第二部分:[常用命令小试] 第三部分:[oracle的安装]
- MySQL的IFNULL函数
MySQL函数里有一个很有用的函数IFNULL,它的形式是IFNULL(fieldA,fieldB),意义是当字段fieldA是NULL时取fieldB,不是NULL时取fieldA的值. 这个函数与 ...
- linux内核——进程管理
在讲进程之前先说一下进程的堆栈的吧: 1.进程的堆栈 内核在创建进程的时候,在创建task_struct的同一时候,会为进程创建对应的堆栈.每一个进程会有两个栈,一个用户栈.存在于用户空间,一个内核栈 ...
- ArcGIS放射状流向地图
今年百度推出了一个百度迁徙,在其他人看是好像是还挺专业的,其实不复杂.下面是百度的迁徙图示例:从图中可以看出从一个城市到另一个城市迁徙的直线路径,多个路径可以反映城市是否为热点城市,即人口流动比较大. ...
- Firefox 之 应用小结
1. 调试脚本 做前端开发的朋友应该对FireFox再熟悉不过了,FireFox有一个附加组件FireBug.在HTML中可以直接写 <script type="tex ...
- Jetty:配置上下文
这篇文件讲述配置Jetty上下文的各种选项. 设置上下文路径 上下文路径是一个URL路径的前缀,用于将一个输入请求相应到相应的上下文.Java Servlet Server的URL通常的格式为:htt ...