C++中虚函数和多态

1.C++中的虚函数

C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。

对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)和一个指向虚函数表的指针(vptr)来实现的。虚函数表,简称为vtbl,虚函数表表对实现多态起着至关重要的作用。在这个表中,主要保存了一个类中的虚函数的地址,这张表解决了继承、覆盖的问题,保证其内容能真实反应实际的函数。每一个包含虚函数的类的实例都包含一个cptr指针,指向虚函数表的首地址。我们可以通过这个指针找到要访问的虚函数的,完成虚函数的调用主要包括:找到虚函数表的首地址(vptr),通过cptr找到要使用虚函数地址,调用虚函数。那么使用虚函数大家总要考虑效率的问题,实际上为了提高效率,C++的编译器是保证虚函数表的指针存在于对象实例中最前面的位置,这是为了保证取到虚函数表的有最高的性能,这意味着我们通过对象实例的地址得到这张虚函数表,然后通过遍历表就可以找到其中的虚函数的地址,然后调用相应的函数。不妨看看下面的代码:

通过这个示例,可以看到,通过强行把&b转成int *,取得虚函数表的地址(vptr),然后,再次取址就可以得到第一个虚函数的地址了,也就是Base::f(),这在上面的程序中得到了验证(把int* 强制转成了函数指针)。通过这个示例,我们就可以知道如果要调用Base::g()和Base::h(),其代码如下:

可以看看虚函数表的图是怎么画的:

            

大家都知道,多态是通过继承实现的,那么我们要说说虚函数继承的问题。继承就涉及到了虚函数的覆盖了,实际上不被覆盖的虚函数和多态又有什么联系呢?这里我们讨论有覆盖的虚函数表是什么样的,假设存在下面的继承关系:

        

看看虚函数表示什么样的:

        

可以发现,Base::f()被覆盖了,这样若把Derive的实例赋值给一个基类Base指针pBase,通过pBase->f();则访问的是子类中的f()也就是完成了多态。那么虚函数表中的内容到底是怎么样的呢?可以看看下面的四句话就会明白!

1.虚函数按照其声明顺序放于表中。

2.父类的虚函数在子类的虚函数前面。

3.覆盖的f()函数被放到了虚表中原来父类虚函数的位置。

4.没有被覆盖的函数依旧。

2.用虚函数实现多态

看看下面的多态的代码:

实现虚函数的代码,一定要切记:一定是基类的指针指向子类的对象的地址。首先试着理解一下用虚函数实现多态的原理,如果实在没理解为什么虚函数能实现多态,又为什么这样实现多态,上网再搜一搜相关的资料!!!

时间: 2024-09-29 08:44:35

C++中虚函数和多态的相关文章

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数、抽象类、虚析构函数、动态创建对象

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数.抽象类.虚析构函数.动态创建对象 一.纯虚函数 1.虚函数是实现多态性的前提 需要在基类中定义共同的接口 接口要定义为虚函数 2.如果基类的接口没办法实现怎么办? 如形状类Shape 解决方法 将这些接口定义为纯虚函数 3.在基类中不能给出有意义的虚函数定义,这时可以把它声明成纯虚函数,把它的定义留给派生类来做 4.定义纯虚函数: class <类名> { virtual <类型> <函

C++ Primer 学习笔记33_面向对象编程(4)--虚函数与多态(一):多态、派生类重定义、虚函数的访问、 . 和-&gt;的区别、虚析构函数、object slicing与虚函数

C++ Primer学习笔记33_面向对象编程(4)--虚函数与多态(一):多态.派生类重定义.虚函数的访问. . 和->的区别.虚析构函数.object slicing与虚函数 一.多态 多态可以简单地概括为"一个接口,多种方法",前面讲过的重载就是一种简单的多态,一个函数名(调用接口)对应着几个不同的函数原型(方法). 更通俗的说,多态行是指同一个操作作用于不同的对象就会产生不同的响应.或者说,多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为. 多态行分

C++学习之路:虚函数与多态

summery:主要有以下几个内容 1.多态 2.静态绑定与动态绑定 3.虚函数 4.虚表指针 5.object slicing与虚函数 6.overload override overwrite的区别   @什么是多态性?  #多态是面向对象程序设计的重要特征之一 #多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为 #多态的实现:  $函数重载 $运算符重载 $模板  $虚函数 前三个都属于静态绑定, 虚函数属于动态绑定 tip: {静态绑定}:绑定过程出现在编译阶段,在

&lt;转&gt;C++继承中虚函数的使用

转自:http://blog.csdn.net/itolfn/article/details/7412364 一:继承中的指针问题. 1. 指向基类的指针可以指向派生类对象,当基类指针指向派生类对象时,这种指针只能访问派生对象从基类继承 而来的那些成员,不能访问子类特有的元素 ,除非应用强类型转换,例如有基类B和从B派生的子类D,则B *p;D  dd; p=&dd;是可以的,指针p只能访问从基类派生而来的成员,不能访问派生类D特有的成员.因为基类不 知道派生类中的这些成员. 2. 不能使派生类

关于C++与Java中虚函数问题的读书笔记

之前一直用C++编程,对虚函数还是一些较为肤浅的理解.可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题. Java中的虚函数 以下是段别人的代码,输入结果竟是Base,这让一直以来用C/C++的我有些莫不着头脑,不是Java里对象是引用吗?C/C++中通过指向基类的指针或引用来指向派生类,那么对于虚函数来说通过基类指针使用的是指向的派生类.但在Java中没有keyword标明虚函数,此时就不是非常明确究竟调用的谁. class base

C++中虚函数工作原理和(虚)继承类…

转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7883531 一.虚函数的工作原理 虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数.典型情况下,这一信息具有一种被称为 vptr(virtual table pointer,虚函数表指针)的指针的形式.vptr 指向一个被称为 vtbl(virtual table,虚函数表)的函数指针数组,每一个包含虚函数的类都关联到 vtbl.当

虚函数 继承 多态

单继承与Data Members 在C++的继承模型中,base class members和derived class members的排列顺序并为强制规定.不同的编译器可能有不同的布局安排.大部分情况下,base class members会安排在derived class members的前面,但base class是virtual base class(base class存在virtual function)除外. 只有继承没有多态 考虑如下程序: class Point2d { pu

C++学习研究之虚函数、多态的实现原理

1. 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数.2. 存在虚函数的类都有一个一维的虚函数表叫做虚表.类的对象有一个指向虚表开始的虚指针.虚表是和类对应的,虚表指针是和对象对应的.3. 多态性是一个接口多种实现,是面向对象的核心.分为类的多态性和函数的多态性.4. 多态用虚函数来实现,结合动态绑定.5. 纯虚函数是虚函数再加上= 0.6. 抽象类是指包括至少一个纯虚函数的类. 纯虚函数:virtual void breathe()=0:即抽象类!必须在子类实现这个函数!

解析C++中虚函数

C++中的一个重要特征是多态即使用同名函数实现不同的功能,多态分为编译时的多态和运行时的多态,编译时的多态主要是指运算符重载和函数重载,而运行时的多态主要是指派生类和虚函数的多态,即使用基类的应用或指针可以引用派生类中的方法(不能引用基类中没有而派生类中新增的方法),如果没有指明是虚函数,指向派生类的指针或引用将会直接调用基类中的方法.这是由于如果定义为虚函数,将会在对象中增加一个虚函数表,来存放虚函数地址,如果派生类重新定义了虚函数,将同时更改虚函数地址,将地址改为指向派生类中的方法. 例如: