`
yaasshole
  • 浏览: 658944 次
文章分类
社区版块
存档分类
最新评论

虚函数

 
阅读更多
虚函数的内存布局
一个拥有虚函数的类内部会有一个成员变量vptr,一个四字节大小的指针,指向虚函数表,虚函数表中记录了该类的各个虚函数的入口地址,如果该类重载了继承的虚函数,那么就存放自己的虚函数地址,否则就是父类的虚函数地址。
class A
{
public:
virtual void f(){};
virtual ~A(){};
};
class B:public A
{
void f(){int i=0;};
};
A* pA=new B();
pA->f();
对于f的调用操作编译器有如下动作:
void B::f()函数解释为void f(B* this);
pA->f()解释为 (*pA->vptr[0])(this);//0是f函数在虚拟函数表格中的索引
所以我们可以看出,虽然指针pA静态类型为A类的指针,但是对于f的调用是依赖于B对象内部的vptr指向的虚拟函数表,而此时函数表内的f函数已经是B类的重载版本,因此这就构成了运行时多态,这个c++的基本特征。
虚继承的内存布局,摘自《c++对话系列》。
class parent { /* whatever */ };
class child1 : public virtual parent { /* whatever */ };
class child2 : public virtual parent { /* whatever */ };
class multi : public child1, public child2 { /* whatever */ };
parent::vptr
parent data
child1::vptr
child1 data
child2::vptr
child2 data
multi::vptr
multi data
在这种复杂的情况下,最底层派生对象内部拥有三个vptr,指向三个虚函数表。
注意,经过我的实验,这种内存布局各种编译器表现不一样,比如vc就是先把child1放在最前面,然后是child2,最后是parent,并且至少vc中,我们可以通过调用static_cast获得各个类型的vptr值,这种典型的应用是在comQueryInterface函数的实现里面。
经过上面的分析,我知道上面的虚继承会带来多个虚函数表以及多个vptr,这是内存上的额外的开销,当然避免了多个顶级父类的内存副本和模棱两可的继承,也有它的好处。
我们可以看看com里面常常出现的多继承带来的对象内存布局
class CPenguin : public IBird, public ISnappyDresser {...};
IBird和ISnappyDresser接口都继承自IUnknown接口,内存布局如下图:
纯虚函数和虚函数的区别
参考 <<Effective C++>> 3th Edition,这里作个简单的概括
纯虚函数分为函数定义和没有函数定义----
没有函数定义的纯虚函数目的是为了让子类继承接口,强制子类实现该函数;
有函数定义的纯虚函数目的是为了让子类继承接口,而父类的实现函数必须在子类重载函数中手动调用
非纯虚函数目的是让子类自动的继承接口和函数实现
虚函数与访问权限
虚函数的重载机制和访问权限是相互独立的,互相没有干扰,但是可以结合使用。
一个private权限的虚函数可以被子类重载,但是子类不能访问父类的虚函数,但是父类可以通过运行时多态的方式来调用子类重载后的虚函数。
一个protected权限的虚函数可以被子类重载,子类也可以访问父类的虚函数
一个public权限的虚函数可以被重载,子类也可以访问
虚函数与设计模式
虚函数和template method模式的结合
这也被称为NVI(non virtual interface)手法。类只暴露非虚函数f,同时提供一个保护或者私有的d_f虚函数,在f函数的视线中调用do_f。派生类重载do_f从而提供自己的独特功能。
Template Method模式的好处就是提供统一的调用框架,在f函数里面,而交给派生类自己订制的行为。比如f函数里面,可以在调用do_f之前与之后添加一些代码,执行内存分配和清除动作。
虚拟函数应该和数据成员一样对待----让他们成为私有的,除非设计需求表明应该有较少的限制。提升它们到更高存取级别比把它们降到更私有的级别更容易些。
分享到:
评论

相关推荐

    构造函数不能声明为虚函数的原因及分析

    1. 从存储空间角度,虚函数对应一个指向vtable虚函数表的指针,这大家都知道,可是这个指向vtable的指针其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有...

    c++虚函数与虚函数表

    学习 C++ 的同志不知道有没有和我一样遇到过这样的困惑:C++中的虚函数到底怎么实现的?在各种继承关系中,虚函数表的结构到底是什么样的?曾经我是很想当然,可是后来在使用ATL的过程中,我发现并不是我想的那样。...

    构造函数不能声明为虚函数,析构函数可以声明为虚函数

    构造函数不能声明为虚函数,析构函数可以声明为虚函数。

    C++虚函数实现原理

    虚函数表中虚函数的分布情况;其中包括发生继承的情况下虚函数表中虚函数的分布情况;

    C++ 多态 虚函数 虚函数表 最是详细

    高质量的C++多态讲解,详细讲解虚函数,虚函数表,虚函数继承,虚函数继承下的内存分配等

    虚函数表工作原理

    虚函数表 对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。 在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容...

    C++虚函数表测试源码

    C++虚函数表的测试代码,用于学习C++虚函数的调用关系。

    c++多态性与虚函数练习题

    2、熟练掌握虚函数的作用及其使用方法。 3、掌握静态关联和动态关联的概念和用法。 4、理解纯虚函数和抽象类的概念和用法。 (二)实验内容 1、定义一个类A,在A中有两个私有的整型变量a和b,定义构造函数对a和b进行...

    c++虚函数使用

    c++虚函数.C++中的虚函数的作用主要是实现了多态的机制。

    虚函数虚表的详解,大家看看!

    个类如果有虚函数,不管是几个虚函数,都会为这个类声明一个虚函数表,这个虚表是一个含有虚函数的类的,不是说是类对象的。一个含有虚函数的类,不管有多少个数据成员,每个数据成员都有一个虚指针,在内存中,存放...

    C++虚函数表解析

    C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际 子类的成员函数。

    指针高级应用_虚函数

    V6.0验证源码 ,分析虚函数的实现过程 ,强制转换的实质 ,多种指针用法,如果完全看懂了相信你的C++,指针会有一个更深刻的认识。希望对大家有用

    C++虚函数及虚函数表解析

    C++虚函数及虚函数表解析,内容详细,分析清晰,推荐给大家。

    c++中子类对象不能调用父类中的虚函数

    c++里,指针和引用是很重要的概念,这个程序不仅对指针和引用做了说明、使用,而且对子类不能继承父类虚函数也做了说明。

    (转)多重继承下的虚函数表

    多态是C++语言中的一项重要的机制,虚函数就是为实现多态而设计的。多态就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”。而虚函数表在...

    C++实验六 多态性和虚函数的应用 课程 实验报告

    C++实验六 多态性和虚函数的应用 课程 实验报告 作业参考的良品!

    利用虚函数计算各种图形面积

    自己设计的图形面积计算程序,利用虚函数计算基类及派生类的图形面积,包括三角形、正方形、长方形、梯形

    c++继承与多态,虚函数实例

    简单例子展示虚函数展现的多态特性,更改一处注释就能对比基类是否是虚函数带来的变化

    用C++实现虚函数

    用C++简单编码实现虚函数,展现虚函数的用法,以及虚析函数的用法 和 判断类的大小(在类中有虚函数的时候,无虚函数的时候)

    c++虚函数表解析(彻底攻克继承和虚函数)

    彻底搞清楚继承是个什么东西 彻底搞清楚虚函数和虚函数表是个什么东西

Global site tag (gtag.js) - Google Analytics