在什么是虚基类情况下定义虚基类?

C++虚基类问题_百度知道
C++虚基类问题
题目:定义一个车(vehicle)基类,具有MaxSpeed、Weight等成员变量,Run、Stop等成员函数,由此派生出自行车(bicycle)类、汽车(motorcar)类。自行车(bicycle)类有高度(Height)等属性,汽车(motorcar)类有座位数(SeatNum)等属性。从bicycle和motorcar派生出摩托...
我有更好的答案
虚基类用于只提供声明接口,由派生类去定义接口。一般是这样使用 vehicle* pv =
//后面那个类是vehicle的派生类 基类对象必须是指针* pv ,不可以是实例化的具体类class vehicle{public: virtual ~vehicle() = 0;
//必须定义vehicle的析构函数否则编译出错,这是规定 virtual void MaxSpeed() = 0; //可以定义也可以不用定义 virtual void Weight() = 0;
//可以定义也可以不定义 virtual void Run() = 0;
//可以定义也可以不定义 virtual void Stop() = 0;
//可以定义也可以不定义};class bicycle : public vehicle{public: virtual void Run() ;
//这里bicycle 修改了Run的接口
//当vehicle* pv = bicycleObject时候,发运行时动态绑定,
//也就是说pv指针指向这个派生类对象的时候,你pv-&Run()
//调用的就是bicycle 类的Run函数,而不再是基类的Run()函数。};class motorcar : public vehicle{ public: virtual void Stop();
virtual void Run();
//如果基类指针指向motorcar ,那么它调用就就是motorcar::Run()
};也就是说基类指针指向什么派生类就调用哪个派生类函数。可是如果派生类没有去修改继承的函数,调用的就是基类的函数.。对了一定要记得,调用未定义的函数是非法的。所以你如果你确定要继承就要修改接口函数,如果你确定有些接口函数不用修改,就要去定义,一定要定义。还有基类虚函数一定要定义。
你所说的车这个“虚基类”并不是一个实现类,也不是类的实例。 其实你可以这么理解: 汽车、自行车、摩托车这几个类之间并没有什么联系,是完全不同的类。只不过有相同的属性而已,例如:汽车有汽车的重量和自行车有自行车的重量,而车是凌驾于“各种车们”之上的概念,它其实是与汽车、自行车、摩托车类一样,都是类。他们唯一的关系是:定义汽车的重量时用到了车的重量这个概念,都继承于车,证明他们都有车的共同属性,但各自的重量可以不同,汽车是1T而自行车是2kg。
总体来说就是,这些汽车、自行车、**车...他们都有这些属性,但属性值可以不同! 上升点高度:子类继承于父类后,会继承父类的属性,而不会继承父类的属性值,同样,各子类间的属性值没有任何关系。
不知道讲明白没~~
为您推荐:
其他类似问题
虚基类的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。要啥自行车?
抽象类和虚基类的定义及用途
抽象类不能实例化对象!
为了让一个类成为抽象类,至少必须有一个纯虚函数。包含至少一个纯虚函数的类视为抽象类!
virtual void lock(void)=0;
virtual void unlock(void)=0;
virtual ~A(void);
//将函数lock()和unlock()初始化为0使它们成为纯虚函数,没有0这个初使化器,它们仅仅是虚函数。
如果子类是一个非抽象类的的话,必须重写父抽象类的所有抽象方法,如果子类是一个抽象类的话,可以重写父抽象类的抽象方法,也可以继承父抽象类的抽象方法~
class x1:virtual public x
//virtual也可以写在public后面
};虚基类可以解决二义性的问题其实说白了就是解决多重多级继承造成的二义性问题。例如有基类B,从B派生出C和D,然后类F又同时继承了C和D,现在类F的一个对象里面包含了两个基类B的对象,如果F访问自己的从基类B那里继承过来的的数据成员或者函数成员那么编译器就不知道你指的到底是从C那里继承过来的B对象呢还是从D那里继承过来的B对象。
于是虚基类诞生了,将C和D的继承方式改为虚继承,那么F访问自己从B那里继承过来的成员就不会有二义性问题了,也就是将F对象里的B对象统一为一个,只有一个基类B对象,下面是一段代码说明了对虚基类的使用。
#include &iostream&
void showa(){cout&&"i="&&i&&}
class B:virtual public A
//此处采用虚继承
class C:virtual public A
//此处采用虚继承
class D:public B,public C//调用析构函数时先调用虚基类的构造函数,然后挨个最后调用基类的析构函数,构造函数反过来
int main()
a.showa();
b.showa();
c.showa();
d.showa();
//cout && "Hello world!" &&
从这个代码我们可以看出B,C,D从A那里继承过来了i这个变量并且它们之间不会有任何影响,如果B和C不是虚继承方式的,那么d.i=4;就不能编译通过了。
创建派生类的对象时:先调用基类构造函数,对象成员构造函数(单选上的,并不太懂),派生类本身构造函数.
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!第七章答案继承、虚基类_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
第七章答案继承、虚基类
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩7页未读,
定制HR最喜欢的简历
你可能喜欢【选择恐惧症】接口?虚基类? - 简书
【选择恐惧症】接口?虚基类?
记得有个朋友跟我讨论过这样的一个问题,说到他刚刚学习接口和虚基类的相关知识时觉得很迷茫,不知道什么时候该用接口,什么时候该使用虚基类。后来慢慢地发现接口能做的事情,虚基类也能够实现,甚至有更多的特点。再后来就慢慢地放弃了接口,把所有的设计和实现都采用虚基类来替代。不能说我这个朋友这样的处理有错,但是就我个人对接口和虚基类的理解来说,这样的做法是有不妥的地方。
所谓的接口简单的来说就是个“门口”,而这个"门口"是安装在某个模块或者服务上,其目的就是为了让外面的世界通过这个“门口”可以访问到模块上的功能或服务。由于是跟外部环境做对接,因此给它定义为--接口。而虚基类则更像一间毛胚房,整个架子已经有了(包括门口),想要什么东西就直接往里面放,但是摆放的东西跟整个架子的设计有关,不是所有的东西都能乱摆,就好像原本规划为洗手间的空间,总不能把床摆在里面吧(当然,你乐意也是可以的。)。
说到这里,其实已经能够感觉到它们的区别是什么了,表面上虚基类感觉更加强大一点,可以像接口那样声明一系列的方法(这里的方法是没有实现体的,在虚基类中我们把这类方法叫“虚方法”),又能定义一些共有的属性;但是,因为虚基类也是一个类型,是必须要继承与它才能够拥有这样的一些特性,所以这就是它的限制和约束。
而接口总的来说是比虚基类要更加灵活一点,因为它没有涉及到类的层面,只跟类中方法绑定,不需要指定其类型。也就是说类型实现了接口中所定义的方法,那么,则可以为外部提供这样的功能。说得通俗一点就是门口你可以随便在哪间房子上开。而虚基类则不具有这样的能力。我们用代码来解释一下上面所说的。
//定义接口
interface IAction
function run();
//定义一个Person类
class Person : IAction
function run()
print("person run...");
//定义一个Dog类
class Dog : IAction
function run()
print("dog run...");
上面代码中定义了一个IAction的接口(一般的高级编程语言中都用interface这个词来表示接口,在Objective-C中则使用了Protocol一词来表示接口,其实也挺贴切,因为要调用接口的功能就是要按照其指定的协议来实现,包括传什么样参数,返回什么值),Person和Dog分别实现了IAction接口,可以看到Person和Dog是两个毫无关系的类型。
如果换作是虚基类则无法将这两种类型关联起来,因为实现的类型必须继承该虚基类,但是,有一种变通的做法就是对要关联的类型进行更高层次的抽象,那上面的例子来说,因为Person和Dog都属于动物,因此我们可以把虚基类定义为Animal类型。则有下面的做法:
//定义虚基类Animal
virtual class Animal
//定义虚方法run
virtual function run() :
//继承于Animal的Person类
class Person : Animal
function run()
print("person run...");
//继承于Animal的Dog类
class Dog : Animal
function run()
print("dog run...");
通过这样的做法确实是能够达到想要的效果, 但是如果你之前已经设计好了一个虚基类,对于后续需要在设计中加入这种不相关的类型,那么你就需要调整之前设计好的虚基类了,明显要花费额外的时间去做一些重构。
所以,设计时要选择使用接口还是虚基类?我个人觉得虚基类不适合作为提供外部调用。因为他与类型结构绑定,日后如果要进行调整就会影响对外行为。但是它可以作为内部某些业务处理的公共封装,配合类工厂模式屏蔽类型上的差异。例如写一个数据存储服务,它可能是文件存储,也可能是数据库存储,我们可以进行如下定义:
//定义数据存储服务的虚基类
virtual class DataStoreService
//定义保存数据的纯虚方法
virtual function saveData(data : Object) :
//定义文件数据存储服务类型
class FileStoreService : DataStoreService
var _file:F
function saveData(data : Object) : void
_file.writeData(data);
_file.save();
//定义数据库存储服务类型
class DatabaseStoreService : DataStoreService
function saveData(data : Object) : void
_db.insertData(data);
_db.flush();
//定义一个数据存储类工厂
class DataStoreFactory
//定义数据存储方式
enum DataStoreType
//获取数据存储服务方法
function getDataStoreService(type : DataStoreType) : DataStoreService
switch (type)
case File:
return new FileStoreService();
case Database:
return new DatabaseStoreService();
如上述代码所示(上面写的都是伪代码,只用于说明意图),只要使用DataStoreFactory然后根据自己需要的存储类型就能获取到不同的存储服务,而返回的类型是定义的虚基类DataStoreService,这样就能够很好地屏蔽FileStoreService和DatabaseStoreService中的一些设计细节,因为对于调用的人来说这些都可以是透明的。
而接口正是我们需要对外提供功能的一个比较好的方案。一来它不跟类型挂钩,二来又能像虚基类中的纯虚函一样可以屏蔽内部实现,对调用者透明不需要他理解里面的实现原理,只管调用和取得结果。第三个就是对于日后内部设计的升级改造时,无需改变接口的定义,只要把内部实现进行调整即可。我们来举个例子,假如之前我们一直使用文件作为主要的存储方式,那么使用接口来实现,可以类似如下代码:
//定义数据存储服务接口
interface IDataStoreService
function saveData(data : Object) :
//定义文件存储服务,该类型不对外公开
class FileStoreService : IDataStoreService
var _file : F
function saveData(data : Object) : void
_file.writeData(data);
_file.save();
//对外公开的Api类型
function getDataStoreSerivce( ) : IDataStoreService
return new FileStoreService( );
值得注意的是,我们在设计时必须是要有一个对外公开的类,否则无法让外部可以访问到内部所提供的接口,上面代码提供公开类就是Api类型。从代码上来看我们的Api类型的getDataStoreService方法只返回了一个IDataStoreService的接口,并不涉及到FileStoreService。所以,当我们在进行改造时,可以直接把文件存储改为数据库存储,也不会对外部调用造成任何影响,如下面代码变更:
//定义数据存储服务接口
interface IDataStoreService
function saveData(data : Object) :
//定义数据库存储服务类型
class DatabaseStoreService : IDataStoreService
function saveData(data : Object) : void
_db.insertData(data);
_db.flush();
//对外公开的Api类型
function getDataStoreSerivce( ) : IDataStoreService
return new DatabaseStoreService( );
回到最初我朋友的那个问题,其实要使用虚基类还是接口来实现功能,这两者其实是没有任何冲突的,最好是两者结合使用,虚基类作为内部封装的公共元素而存在,可以根据领域的不同划分多个不同的虚基类,而在虚基类中定义的某项功能需要暴露给外界调用时,则可以使用接口来定义,同样根据不同的领域可以划分多个不同的接口。还是根据上面的例子,我们把虚基类和接口相结合,形成一个完整的数据存储服务模块:
//定义数据存储服务接口
interface IDataStoreService
function saveData(data : Object) :
//定义数据存储服务的虚基类
virtual class DataStoreService : IDataStoreService
//实现接口方法
function saveData(data : Object) : void
//由于实现接口的类型不允许不实现接口方法,
//因此这里保留一个空实现方法,等待它的子类重写该方法。
//定义文件数据存储服务类型
class FileStoreService : DataStoreService
var _file:F
function saveData(data : Object) : void
_file.writeData(data);
_file.save();
//定义数据库存储服务类型
class DatabaseStoreService : DataStoreService
function saveData(data : Object) : void
_db.insertData(data);
_db.flush();
//定义一个数据存储类工厂
class DataStoreFactory
//定义数据存储方式
enum DataStoreType
//获取数据存储服务方法
function getDataStoreService(type : DataStoreType) : DataStoreService
switch (type)
case File:
return new FileStoreService();
case Database:
return new DatabaseStoreService();
//对外公开的Api类型
function getDataStoreSerivce( ) : IDataStoreService
return DataStoreFactory.getDataStoreService(DataStoreType.Database);
接口 用于提供给外部调用的入口,根据功能领域的不同来划分不同的接口。其不与类型绑定,只跟类型中的成员方法相关。方便日后内部的升级改造,不影响对外提供的服务。
虚基类 用于内部封装类型的共有特征,由于虚基类不能直接实例化,因此可以起到屏蔽子类实现细节的效果。搭配类工厂来实现不同业务分派给不同的子类来进行处理。
在很多高级语言中两者都有定义(即使没有也可以代码层面去模仿和约定),善用这两种定义能够使自己的设计变得简单,结构变得清晰。
让不可能变为可能
1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io的语法,虚拟机方面的语法。 1、一个&.java&源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个publ...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金相信有很多朋友...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金 相信有很多...
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式...
百战程序员_ Java1573题 QQ群:034603 掌握80%年薪20万掌握50%年薪10万 全程项目穿插, 从易到难,含17个项目视频和资料持续更新,请关注www.itbaizhan.com 国内最牛七星级团队马士兵、高淇等11位十年开发经验专...
女儿让我带她去练跳绳,我爽快的答应了。晚饭后,带上二宝,我们仨就来到了广场,开始跳绳了,第一次一分钟跳了45个,第二次跳了62个,我对她说,休息一会儿保持体力一会儿再跳,她说:“妈妈我感觉我跳不到160”我对她说,你看你开始的时候跳了45个,第二次就跳到了62个,多大的...
今天是出行的第三天,住在推门就是南湖的卿一位客栈,白天客栈门前小路上人流不息,院里却非常安静!我喜欢他们家宽大的木质桌子,桌子下面养的有鱼,很适合读书晒太阳! 我试想自己天天住在这样的地方该多自在,转念一想如果天天这样在一个村子里,吃饭睡觉晒太阳,我也会觉得无聊吧,那么,做...
1. Zepto库和JQ区别 Zepto相对jQuery更加轻量,主要用在移动端,jQuery也有对应的jQuerymobile移动端框架 2、移动端最小触控区域是多大? 移动端的点击事件的有延迟,时间是多久,为什么会有? 怎么解决这个延时?(click 有 300ms 延...
不能说是最喜欢哪一种人,因为我个人是比较中庸的那一型,但突然发觉我最不能忍受这样一种人:完全不能控制自己脾气或情绪的人。
随想那触摸不到的远方, 心里焦灼等待的彷徨, 世人无从诉说的恐慌; 曾经以为的绚烂梦想, 终不过醉生梦死的忧伤, 最终风残云卷的遗忘; 黑夜苍穹划过的星光, 孤独的弥望, 落下点点白霜; 漫过痛彻心扉的绝望, 谁不曾经历的过往, 是指尖托起的希望。 (PS:简书上第一篇随文...豆丁微信公众号
君,已阅读到文档的结尾了呢~~
理解虚基类、虚函数与纯虚函数的概念引言一直以来都没有写过一篇关于概念性的文章,因为我觉得这些概念性的东西书本上都有并且说的也很详细写来也无用,今天突发奇想想写一写,下面就和大家讨论一下虚基类、虚函数与纯虚函数 一看名字就让人很容易觉得混乱。不过不要紧待看完本文后你就会理解了。正文虚基类在说明其作用前先看一段代码class A publicint iValue; ;class B:public A publicvoid bPrintf
This is cl..
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
理解虚基类、虚函数与纯虚函数的概念
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='http://www.docin.com/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口

我要回帖

更多关于 虚基类定义 的文章

 

随机推荐