虚基类 虚函数 纯虚函数讲解

news/2024/7/4 1:41:02 标签: class, 编译器, 交通, 工具, c
cle class="tags" href="/tags/CLASS.html" title=class>class="baidu_pl">
cle_content" class="tags" href="/tags/CLASS.html" title=class>class="article_content clearfix">
content_views" class="tags" href="/tags/CLASS.html" title=class>class="htmledit_views">  

虚基类

在说明其作用前先看一段代码

class="tags" href="/tags/CLASS.html" title=class>class="dp-highlighter">
class="tags" href="/tags/CLASS.html" title=class>class="bar">

从代码中可以看出类B C都继承了类A的iValue成员,因此类B C都有一个成员变量iValue ࿰c;而类D又继承了B C࿰c;这样类D就有一个重名的成员 iValue(一个是从类B中继承过来的࿰c;一个是从类C中继承过来的).在主函数中调用d.iValue 因为类D有一个重名的成员iValueclass="tags" href="/tags/BianYiQi.html" title=编译器>编译器不知道调用 从谁继承过来的iValue所以就产生的二义性的问题.正确的做法应该是加上作用域限定符 d.B::iValue 表示调用从B类继承过来的iValue。不过 类D的实例中就有多个iValue的实例࿰c;就会占用内存空间。所以C++中就引用了虚基类的概念࿰c;来解决这个问题。

class="tags" href="/tags/CLASS.html" title=class>class="dp-highlighter">
class="tags" href="/tags/CLASS.html" title=class>class="bar">

在继承的类的前面加上virtual关键字表示被继承的类是一个虚基类࿰c;它的被继承成员在派生类中只保留一个实例。例如iValue这个成员࿰c;从类 D这个角度上来看࿰c;它是从类B与类C继承过来的࿰c;而类B C又是从类A继承过来的࿰c;但它们只保留一个副本。因此在主函数中调用d.iValue时就不 会产生错误。

虚函数
还是先看代码

class="tags" href="/tags/CLASS.html" title=class>class="dp-highlighter">
class="tags" href="/tags/CLASS.html" title=class>class="bar">

大家以为这段代码的输出结果是什么?有的人可能会马上回答funPrint of class="tags" href="/tags/CLASS.html" title=class>class A 与 funPrint of class="tags" href="/tags/CLASS.html" title=class>class B 因为第一次输出是引用类A的实 例啊࿰c;第二次输出是引用类B的实例啊。那么我告诉你这样想就错啦࿰c;答案是funPrint of class="tags" href="/tags/CLASS.html" title=class>class A 与 funPrint of class="tags" href="/tags/CLASS.html" title=class>class A 至于为什么输出 这样的结果不在本文讨论的范围之内;你就记住࿰c;不管引用的实例是哪个类的当你调用的时候系统会调用左值那个对象所属类的方法。比如说 上面的代码类A B都有一个funPrint 函数࿰c;因为p是一个A类的指针࿰c;所以不管你将p指针指向类A或是类B࿰c;最终调用的函数都是类A的funPrint 函数。这就是静态联篇࿰c;class="tags" href="/tags/BianYiQi.html" title=编译器>编译器在编译的时候就已经确定好了。可是如果我想实现跟据实例的不同来动态决定调用哪个函数呢?这就须要用到 虚函数(也就是动态联篇)

class="tags" href="/tags/CLASS.html" title=class>class="dp-highlighter">
class="tags" href="/tags/CLASS.html" title=class>class="bar">

在基类的成员函数前加virtual关键字表示这个函数是一个虚函数࿰c;所谓虚函数就是在编译的时候不确定要调用哪个函数࿰c;而是动态决定将要调 用哪个函数࿰c;要实现虚函数必须派生类的函数名与基类相同࿰c;参数名参数类型等也要与基类相同。但派生类中的virtual关键字可以省略࿰c;也表 示这是一个虚函数。下面来解决一下代码࿰c;声明一个基类的指针(必须是基类࿰c;反之则不行)p࿰c;把p指向类A的实例a࿰c;调用funPrint函数࿰c;这 时系统会判断p所指向的实例的类型,如果是A类的实例就调用A类的funPrint函数࿰c;如果是B类的实例就调用B类的funPrint函数。

纯虚函数
与其叫纯虚函数还不如叫抽象类,它只是声明一个函数但不实现它࿰c;让派生类去实现它,其实这也很好理解。

class="tags" href="/tags/CLASS.html" title=class>class="dp-highlighter">
class="tags" href="/tags/CLASS.html" title=class>class="bar">
class="tags" href="/tags/CLASS.html" title=class>class="tools">   

如上代码࿰c;定义了一个class="tags" href="/tags/JiaoTong.html" title=交通>交通class="tags" href="/tags/GongJu.html" title=工具>工具类(Vehicle)࿰c;类中有一函数可打印出class="tags" href="/tags/JiaoTong.html" title=交通>交通class="tags" href="/tags/GongJu.html" title=工具>工具的轮胎个数࿰c;但class="tags" href="/tags/JiaoTong.html" title=交通>交通class="tags" href="/tags/GongJu.html" title=工具>工具很多轮胎个数自然也就不确定࿰c;所以 就把它定义为纯虚函数,也就是光定义函数名不去实现它࿰c;类Camion继承了Vehicle并实现了里面的代码࿰c;打印出有4个轮胎。Bike类也是一样。 有一点须要注意一下࿰c;纯虚函数不能实化化࿰c;但可以声明指针。


总结

虚基类
1, 一个类可以在一个类族中既被用作虚基类࿰c;也被用作非虚基类。
2, 在派生类的对象中࿰c;同名的虚基类只产生一个虚基类子对象࿰c;而某个非虚基类产生各自的子对象。
3, 虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。
4, 最派生类是指在继承结构中建立对象时所指定的类。
5, 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用;如果未列出࿰c;则表示使用该虚基类的缺省构造函数。
6, 从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生 类的构造函数调用虚基类的构造函数࿰c;而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略࿰c;从而保证对虚基类子对象 只初始化一次。
7, 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时࿰c;虚基类的构造函数先于非虚基类的构造函数执行。

虚函数
1, 虚函数是非静态的、非内联的成员函数࿰c;而不能是友元函数࿰c;但虚函数可以在另一个类中被声明为友元函数。
2, 虚函数声明只能出现在类定义的函数原型声明中࿰c;而不能在成员函数的函数体实现的时候声明。
3, 一个虚函数无论被公有继承多少次࿰c;它仍然保持其虚函数的特性。
4, 若类中一个成员函数被说明为虚函数࿰c;则该成员函数在派生类中可能有不同的实现。当使用该成员函数操作指针或引用所标识的对象时 ࿰c;对该成员函数调用可采用动态联编。
5, 定义了虚函数后࿰c;程序中声明的指向基类的指针就可以指向其派生类。在执行过程中࿰c;该函数可以不断改变它所指向的对象࿰c;调用不同 版本的成员函数࿰c;而且这些动作都是在运行时动态实现的。虚函数充分体现了面向对象程序设计的动态多态性。 纯虚函数 版本的成员函数࿰c;而且这些动作都是在运行时动态实现的。虚函数充分体现了面向对象程序设计的动态多态性。

纯虚函数
1, 当在基类中不能为虚函数给出一个有意义的实现时࿰c;可以将其声明为纯虚函数࿰c;其实现留待派生类完成。
2, 纯虚函数的作用是为派生类提供一个一致的接口。
3, 纯虚函数不能实化化࿰c;但可以声明指针。

cle>

http://www.niftyadmin.cn/n/791164.html

相关文章

先说首先想到的,URL编码问题

某一天我在测试代码的时候突然发现,程序下载下来的xml文件倒确实是xml文件,但是里面只有一个根节点。 也就是说,联网正常,但是获取内容失败了。 因为API一共就三个属性,最后一个是日子,肯定没错&#xff0c…

Android中自定义Activity和Dialog的位置大小背景和透明度等

1.自定义Activity显示样式 先在res/values下建colors.xml文件&#xff0c;写入&#xff1a; Xhtml代码 <?xml version"1.0" encoding"utf-8"?> <resources> <!-- 设置透明度为56%(9/16)左右 --> <color name"tr…

jq 判断IE6

if ($.browser.msie && ($.browser.version "6.0") && !$.support.style) { //代码 } 转载于:https://www.cnblogs.com/baixc/p/3620839.html

SwipeLayout 如何按照权限要求隐藏菜单项(按菜单显示比例动态设置rightViewWidth)

使用的SwipeLayout的地址如下&#xff1a; https://github.com/fanrunqi/SwipeLayout 这个布局挺好用的不过你得手动指定SwipeLayout第二个子布局的width“具体数值”。现在我如果有三个子菜单&#xff0c;这是如果用户权限规定我只能有一个显示该如何破&#xff1f; 如果单…

C++函数重载深度剖析

——每个现象后面都隐藏一个本质&#xff0c;关键在于我们是否去挖掘 写在前面&#xff1a; 函数重载的重要性不言而明&#xff0c;但是你知道C中函数重载是如何实现的呢&#xff08;虽然本文谈的是C中函数重载的实现&#xff0c;但我想其它语言也是类似的&#xff09;&#xf…

流行的框架与新技术

1、谈谈你对Struts的理解。 答: 1. struts是一个按MVC模式设计的Web层框架&#xff0c;其实它就是一个大大的servlet&#xff0c;这个Servlet名为ActionServlet&#xff0c;或是ActionServlet的子类。我们可以在web.xml文件中将符合某种特征的所有请求交给这个Servlet处理&…

Android - ViewPager进阶篇之动态刷新

http://www.jianshu.com/p/863297e782c3 其中遇到问题&#xff1a; 1.第一次加载的fragment 在第二次动态更改后会出现在viewPager中。 解决&#xff1a; public class TabAdapter extends FragmentStatePagerAdapter 原来是继承&#xff1a;FragmentPagerAdapter 怀疑缓存…

前置(后置)++ /--与+/-在不同编译器下运算方式不同

——Dont believe in magic !Understand what your program do ,how they do . 引言 昨晚一时兴起&#xff0c;我脑子就问自己下面的代码会输出什么&#xff0c;也不知道我脑子为什么有这个代码模型&#xff0c;只是模糊的有些印象&#xff1a; view sourceprint?01#include &…