类中的成员函数分为静态成员函数非静态成员函数,而非静态成员函数又分为普通函数虚函数

Q: 为什么使用虚函数

A: 使用虚函数,我们可以获得良好的可扩展性。在一个设计比较好的面向对象程序中,大多数函数都是与基类的接口进行通信。因为使用基类接口时,调用基类接口的程序不需要改变就可以适应新类。如果用户想添加新功能,他就可以从基类继承并添加相应的新功能。

Q: 简述C++虚函数作用及底层实现原理

A: 要点是要答出虚函数表虚函数表指针的作用。

虚函数是用来实现动态绑定的。

C++中虚函数使用虚函数表和虚函数表指针实现,虚函数表是一个类的虚函数的地址表,用于索引类本身以及父类的虚函数的地址,假如子类重写了父类的虚函数,则对应在虚函数表中会把对应的虚函数替换为子类的函数的地址(子类中可以不是函数,但是必须同名);虚函数表指针存在于每个对象中(通常出于效率考虑,会放在对象的开始地址处),它指向对象所在类的虚函数表的地址;在多继承环境下,会存在多个虚函数表指针,分别指向对应不同基类的虚函数表。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

虚函数表是每个(有虚函数的)对应一个。虚函数表指针是每个对象对应一个。

虚函数表里只能存放虚函数,不能存放普通函数。

如果一个函数不是虚函数,那么对它的调用(即该函数的地址)在编译阶段就会确定。调用虚函数的话(它的地址)要运行时才能确定。

虚函数的函数入口是动态绑定的。在运行时,程序根据基类指针指向的实际对象,来调用该对象对应版本的函数。(用该对象虚函数表指针找到其虚函数表,进而调用不同的函数。)(只有是虚函数的情况下才会这么做(用虚函数表指针去查虚函数表)。非虚函数直接就调用自己的。)

follow up:

1. 为什么需要虚析构函数?(什么情况下要用虚析构函数?)

在存在类继承并且析构函数中需要析构某些资源时,析构函数需要是虚函数。否则若使用父类指针指向子类对象,在delete时只会调用父类的析构函数,而不能调用子类的析构函数,造成内存泄露。

2. 一个对象访问普通成员函数和虚函数哪个更快?

访问普通成员函数更快,因为普通成员函数的地址编译阶段就已确定,因此在访问时直接调用对应地址的函数;

而虚函数在调用时,需要首先在虚函数表中寻找虚函数所在地址,因此相比普通成员函数速度要慢一些。

3. 析构函数一定是虚函数吗?

不一定。1. 虚函数效率相对要低一些;2. 有些类并没有子类,没必要用虚析构函数。

4. 内联函数、构造函数、静态成员函数可以是虚函数吗?

都不可以。

内联函数(inline)需要在编译阶段展开(在编译时就已经确定了),而虚函数是运行时动态绑定的,编译时无法展开,因此是矛盾的;

构造函数在进行调用时还不存在父类和子类的概念,父类只会调用父类的构造函数,子类调用子类的,因此不存在动态绑定的概念(先有父类才能有子类,构造父类的时候子类还不存在,子类都还没有怎么可能在父类里动态调用子类);

静态成员函数(static)是以为单位的函数,与具体对象无关,虚函数是与对象动态绑定的,因此是两个矛盾的概念;

5. 构造函数中可以调用虚函数吗?

可以,但是没有意义,起不到动态绑定的效果。父类构造函数中调用的仍然是父类版本的函数,子类中调用的仍然是子类版本的函数。

6. 简述C++中虚继承的作用及底层实现原理?

虚继承用于解决多继承条件下的菱形继承问题,底层实现原理与编译器相关,一般通过虚基类指针实现,即各对象中只保存一份父类的对象,多继承时通过虚基类指针引用该公共对象,从而避免菱形继承中的二义性问题。

ref:

http://blog.csdn.net/haoel/article/details/1948051

http://songlee24.github.io/2014/09/02/cpp-virtual-table/

http://www.cuiyongjian.com/post-199.html   【分析的很有逻辑】

http://www.guokr.com/blog/469006/

C++虚函数原理的更多相关文章

  1. C++ 虚函数畅谈

    0x01:前言 虚函数是C++里最重要的概念之一,并且是判定C++是否入门的一个热门问题.今天这篇文章简单谈谈虚函数. 0x02:虚函数简介 虚函数可以被子类实现函数所覆盖. virtual是关键字, ...

  2. c++ 深入理解虚函数

    为什么使用虚函数?什么是虚函数?虚函数是为了解决什么问题? 面向对象的三大特征: 封装 多态 继承 普通虚函数 虚析构函数 纯虚函数 抽象类 接口类 隐藏 vs 覆盖 隐藏与覆盖之间的关系 早绑定和晚 ...

  3. C++虚函数总结

    为什么使用虚函数?什么是虚函数?虚函数是为了解决什么问题? 面向对象的三大特征: 封装 多态 继承 普通虚函数 虚析构函数 纯虚函数 抽象类 接口类 隐藏 vs 覆盖 隐藏与覆盖之间的关系 早绑定和晚 ...

  4. 虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte

    #include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout < ...

  5. 【高级】C++中虚函数机制的实现原理

    多态是C++中的一个重要特性,而虚函数却是实现多态的基石.所谓多态,就是基类的引用或者指针可以根据其实际指向的子类类型而表现出不同的功能.这篇文章讨论这种功能的实现原理,注意这里并不以某个具体的编译器 ...

  6. 类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)

    原理分析 当调用一个虚函数时, 编译器生成的代码会调用 虚表地址[0](param1, param2)这样的函数. 已经不是在调用函数名了. 当我们将虚表地址[n]中的函数实现改为另外的函数, 虚函数 ...

  7. 漫谈 C++ 虚函数 的 实现原理

    文中讲述的原理是推理和探讨 , 和现实中的实现不一定完全相同 . C++ 的 虚函数 , 编译器 会 生成一个 虚函数表 . 虚函数表, 实际上是 编译器 在 内存 中 划定 的 一块 区域, 用于存 ...

  8. C++虚函数工作原理

    一.虚函数的工作原理      虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数.典型情况下,这一信息具有一种被称为 vptr(virtual table poi ...

  9. C++ 类的多态三(多态的原理--虚函数指针--子类虚函数指针初始化)

    //多态的原理--虚函数指针--子类虚函数指针初始化 #include<iostream> using namespace std; /* 多态的实现原理(有自己猜想部分) 基础知识: 类 ...

随机推荐

  1. Java性能调优:利用JMC进行性能分析

    JMC, 即Java任务控制(Java Mission Control)是从Java7(7u40)和 Java8 的商业版本包括一项新的监控和控制特性. JMC 程序 (JDK_HOME\bin目录下 ...

  2. TemplateBinding和Binding的区别

    定义 TemplateBinding是为了某个特定场景优化出来的数据绑定版本--需要把ControlTemplate里面的某个Property绑定到应用该ControlTemplate的控件的对应Pr ...

  3. 二叉查找树 Java实现

    定义: 一棵二叉查找树是一棵二叉树,每个节点都含有一个Comparable的键(以及对应的值). 每个节点的键都大于左子树中任意节点的键而小于右子树中任意节点的键. 树的术语: Name Functi ...

  4. Golang gRPC 和 gRPC-gateway 结合使用

    一.安装 go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway go get -u github.com/g ...

  5. Mac 硬盘中各个文件夹详解

    打开Macintosh HD你会发现内中有四个文件夹(一般情况下,隐藏文件夹是不可见的,而且,可能会更多,比如安装xcode后会有developer文件夹). 分别有——应用程序(Applicatio ...

  6. mariadb(mysql)从库relaylog损坏无法同步的处理方法

    故障说明 晚上备用服务器自动重启,收到报警,备用服务器上的mariadb从库无法去同步主库.启动mariadb后,报如下错误(重点看红色字体)  mariadb_1 | -- :: [Note] Pl ...

  7. Ionic APP 热更新

    开门见山,本文主题:cordova-hot-code-push 作用:cordova热更新插件,提供了在应用程序中对基于Web的内容进行自动更新的功能. GitHub地址:https://github ...

  8. Head First Python学习笔记2——文件与异常

    文件处理 1.用open()就可以打开文件,但是请注意:文件里有中文请设置编码,如 :open("filepath","r",encoding="ut ...

  9. MySQL 中 You can't specify target table '表名' for update in FROM clause错误解决办法

    在MySQL中,写SQL语句的时候 ,可能会遇到You can't specify target table '表名' for update in FROM clause这样的错误,它的意思是说,不能 ...

  10. java基础之运算符与语句

    一.运算符 1.算数运算符 运算符 名称 举例 + 加法 A等于10,B等于3 则A+B=13 - 减法 A等于10,B等于3 则A-B=7 * 乘法 A等于10,B等于3 则A*B=30 / 除法 ...