• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > c++中虚函数的实现详解

c++中虚函数的实现详解

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c++ 虚函数详解,c++指针详解,c++编程实例详解,c++关键字详解,c++编程实例详解pdf等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

前言

c++ 分为编译时多态和运行时多态。运行时多态依赖于虚函数,大部分人或许听说过虚函数是由虚函数表+虚函数指针实现的,但,真的是这样吗?虽然 c++ 规范有着复杂的语言细节,但底层实现机制却任由编译器厂商想象。(没准某种特殊的处理器电路结构原生支持虚函数,没准这个处理器压根不是冯纽曼型,或者将来厂商发明了比虚函数表更有效率的数据结构。)

虚函数表

封装把实例的数据和操作结合在了一起,但实例本身只有数据,没有函数,同一个类的函数是共享的。我们通过一个例子来间接证明这一点

class Base1
{
public:
 int a;
 void func() { cout << "heel" << endl; }
};

Base1 b1;
cout << sizeof(b1) << endl;
</div>

打印

4
</div>

如果类中有虚函数,则会在对象中加入一个虚函数指针,该指针指向一个虚函数表,表中是各个虚函数的地址。

+--------+    +---------+
| pvtbl |------>| vfunc1 |
+--------+    +---------+
| data1 |    | vfunc2 |
+--------+    +---------+
| ...  |    | ...   |
</div>

当子类继承父类时,会依次覆盖虚函数表中的各个项,如果子类没有重写某项,那该项就保留。当实例化对象后,虚函数指针就作为一个隐藏数据存在于实例中。如果通过父类指针调用普通成员函数,由于普通函数和类型绑定在一起,所以仍会调用父类成员函数;如果通过父类指针调用虚函数,则会通过对象的虚指针找到虚函数表(即子类的虚函数表),定位虚函数项,实现多态。

原理是不是很简单?c++ 就是通过这种看似原始的方式实现高级抽象。以上是编译器的通用做法,我手上的 Visual Studio 2013 编译器就是这么做的,为了提高性能,VS 保证虚函数指针存在于对象实例中最前面位置(历史上也有编译器不这么做,好像是 Borland 的?)。

Visual Studio 2013 中的实现

来一个例子(能这么写是因为我已知了 Visual Studio 2013 编译后对象的内存布局)

#include <iostream>
using namespace std;

class Base 
{
public:
 typedef void (*func)();
 virtual void func1() { cout << "Base::func1" << endl; }
 virtual void func2() { cout << "Base::func2" << endl; }
 virtual void func3() { cout << "Base::func3" << endl; }
};

class Derived: public Base
{
public:
 virtual void func1() { cout << "Derived::func1" << endl; }
 virtual void func3() { cout << "Derived::func3" << endl; }
};

int main()
{
 Base b, b1;
 int** pvirtualtable1 = (int**)&b;
 cout << "Base object vtbl address: " << pvirtualtable1[0] << endl;
 int** pvirtualtable11 = (int**)&b1;
 cout << "another Base object vtbl address: " << pvirtualtable11[0] << endl;
 cout << "function in virtual table" << endl;
 for (int i = 0; (Base::func)pvirtualtable1[0][i] != NULL; ++i)
 {
 auto p = (Base::func)pvirtualtable1[0][i];
 p();
 }
 cout << endl;

 Derived d;
 int** pvirtualtable2 = (int**)&d;
 cout << "Derived object vtbl address: " << pvirtualtable2[0] << endl;
 cout << "function in virtual table" << endl;
 for (int i = 0; (Base::func)pvirtualtable2[0][i] != NULL; ++i)
 {
 auto p = (Base::func)pvirtualtable2[0][i];
 p();
 }
 cout << endl;
}
</div>

打印

Base object pvtbl address: 0029DA58
another Base object pvtbl address: 0029DA58
function address in virtual table
Base::func1
Base::func2
Base::func3

Derived object pvtbl address: 0029DB20
function address in virtual table
Derived::func1
Base::func2
Derived::func3
</div>

可以看到,同一类型不同实例的虚函数表是相同的,继承之后,子类有了自己的虚函数表,表也有相应的更新(Derived::func1, Derived::func3),表中未重写的项还保留为原值(Base::func2)。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

</div>
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C++ 中函数重载、覆盖与隐藏详解
  • C++中函数重载实例详解
  • C++模版函数详解
  • c++中虚函数的实现详解
  • C++函数重载详解及实例代码
  • 详解设计模式中的中介者模式在C++编程中的运用
  • 详解C++中new运算符和delete运算符的使用
  • 详解C++编程中向函数传递引用参数的用法
  • 详解C++编程中数组的基本用法
  • 详解C++编程中的嵌套类的声明与其中的函数使用

相关文章

  • 2017-05-28C语言经典算法例题求100-999之间的“水仙花数
  • 2017-05-28异步http listener 完全并发处理惩罚http恳求的小例子
  • 2017-05-28C++中抽象类和接口的区别介绍
  • 2017-05-28C++ 11实现检查是否存在特定的成员函数
  • 2017-05-28C++设计类不能被继承的方法实例讲解
  • 2017-05-28详解C++编程中的文件流与字符串流
  • 2017-05-28解析C语言中位字段内存分配的问题
  • 2017-05-28C++实现当前时间动态显示的方法
  • 2017-05-28C++中运算符 &和&&、|和|| 的详解及区别
  • 2017-05-28Cocos2d-x学习笔记之CCScene、CCLayer、CCSprite的默认坐标和默认锚点实验

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 浅谈几种常见语言的命名空间(Namespace)
    • c++获取sqlite3数据库表中所有字段的方法小结
    • 浅析顺序结构存储的栈
    • 详解C++编程中对于函数的基本使用
    • 大家注意vector, list, set, map成员函数erase
    • c语言 跳台阶问题的解决方法
    • C++的template模板中class与typename关键字的区别分析
    • C语言/C++如何生成随机数
    • 基于getline()函数的深入理解
    • C++中用new创建二维数组和指针数组实例代码

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有