C++的高手请指点下多态问题。
class Member{
public:
virtual void sports(){cout<<"Sports!";}
};
class Father: public Member{
public:
virtual void sports(){cout<<" Badminton!";}
};
class Mother: public Member{
public:
virtual void sports(){cout<<"Aerobics!";}
};
class Children: public Member{
public:
virtual void sports(){cout<<"Doing skipping!";}
};
问题一:两种写法对于指针pa来说是等价的;用哪一种取决于你是否需要让子类B的实例匿名化。
例如,后续代码中若需要b.foo();呼叫子类B的特定成员函数(或变量),则应该采用第一种方式。
问题二:引用写成A& ra=b;是对的,使用时采用“."操作符,例如 ra.foo();
先用指针再引用,也是可以的,*pa代表的就是实例b,没有必要绕一次。
首先在有虚函数的类中,都保存有一个虚函数表,这个虚函数表不会因为类的对象而变化,也就是说实际是虚函数是static的,是属于类的。在基类和子类中各保存有一张虚函数表,注意,各保存有一张虚函数表。而且虚函数的地址会安排在类中所有成员的最前面。
如果子类没有重写父类的虚函数表,则子类的虚函数表的地址顺序是:基类的虚函数地址,子类的其他虚函数地址。可以看到子类中虚函数表中,基类虚函数的地址在最前面。
如果子类重写了父类的虚函数表时,则子类的虚函数表的地址顺序是:被重定义的基类的虚函数,子类的其他虚函数地址,可以看到基类的虚函数地址,被子类重新定义了的函数地址所覆盖,因此在使用A *p=new B();的时候,基类的指针p就会新先指到被重定义的基类的虚函数的位置,这就是能调用到了子类的虚函数的原因。注意A *p=new B();之后,指针p指向的是子类B的地址,而指针的类型仍为A而已,因此其地址已经发生变化。指针的类型决定指针所能访问的成员,也就是子类的成员,在基类中是不可见的。
通过对上面讲解之后,我们再来看你的问题
pb = static_cast<B *>(a);
把基类指针a强制转换为子类子针,然后再赋给子类指针pb,这时要注意pb指向了基类的地址,也就是说pb和a指向的是相同的地址,也就是指向了基类。因此在使用pb->fun()调用fun的时候,因为fun是虚函数,而虚函数是排在类中所有成员的最前面的,因此这时访问的会是基类的虚函数表中的虚函数,也就是为什么fun如果是虚函数的时候,会输出A::fun()的原因。如果fun不是虚函数,那么这时就不存在什么虚函数表的问题了,这时的问题是,子类的同名函数fun隐藏了基类的同名fun函数,因此再使用pb->fun()的时候,会访问到子类的fun函数,这就是为什么fun若不是虚函数,会输出B::fun()的原因。
第二个问题:把基类指针强制转换为子类指针时的成员问题
static_cast<B *>(a);
经过这个转换之后,基类指针a就成为子类指针,因此他就拥有了子类所拥有的成员,也就是可以访问子类中的成员了,比如可以访问子类中b_fun()函数,比如static_cast<B *>(a)->b_fun();这时就会输出B::b_fun。但这里要注意,虽然static_cast<B *>(a)被强制转换为子类指针了,但指针a还是指向原来的地方 ,也就是说a还是是基类指针,不能使用a来访问子类的成员,也就是说a->b_fun()是错误的。
基类A定义了一个虚函数 virtual void fun(),那么编译器在编译的时候,自动会为类A生成一个名叫“__vfptr”的成员常量指针,是一个函数指针,排在类成员的最前面。这个函数指针指向类A对应的虚函数表(vftable),该虚函数表存储了A::fun()和类A的其他虚函数地址。
在实例化A的对象a时,编译器自动在a对象的前面加上“__vfptr”成员指针(通过VC单步调试可以看出来),它指向A的虚函数表(vftable)。派生类B继承A之后,会将基类的虚函数表继承过来,并将自己定义的虚函数添加到虚函数表中,这样就形成了派生类B的虚函数表,在编译的时候,编译器也会自动会在派生B类的前面加上“__vfptr”的指针成员,指向B的虚函数表。
基类和派生类的指针之前类型转换,会产生指针切割,通常基类指针指向的内存域会比派生类指向的内存域要小;这样基类的指针指向派生类时,就缩小了内存域,这样向上转换,直接赋值就行,不需要强制类型转换;如果将派生类指针指向基类的对象,派生类的指针的指向的内存域会缩小,这样就需要进行强制类型转换。如问题的代码所示 pb = static_cast<B *>(a);
回答以上提出的几个问题:
pb->fun(); 调用的是A::fun(),理由是基类A实例化对象a时,生成一个“__vfptr”成员指针,指向A的虚函数表,A的虚函数表中存在A::fun()函数。
此时将B的对象指针pb强制转换类型指向a,产生了地址切割,对于m_b这个派生类定义的成员来说,它的值是不可预期的。此时pb->__vfptr也同时被赋予a->__vfptr,指向A的vftable,调用pb->fun()时,实际上调用了A虚函数表里面的A::fun()。对于A::fun()不为virtual时,也就不会存在虚函数表中,这样B::fun();是将基类A::fun()实现隐藏了,故A::fun()不为虚函数时,pb->fun()调用的是B::fun()。
b 里改写了的父类函数, 只要父类函数是 virtual 就要用父类的 virtual函数。
父类函数不是 virtual 才用子类改写的父类函数。
A的变量m_a 是A 的,B 的变量m_a 是 B 的. B 无m_a 时,才用 A的。
一般来说,没有标明区域符的(::),就直接默认为子类的。
要调用父类的,就要有::来标明
很简单,用VC6.0进行debugger,可以断点,给出的错误分析很详细!这是我的一些建议,希望对你有点帮助!谢谢…
请高手指点下健身计划~谢谢。好的一定加分哦!
另外,在健身房有些动作也会有巡场教练给予协助与保护,这对练力量挺重要的,因为,就比如说胸肌的卧推罢,想长力量就要冲一冲对自己来说大的重量(比如只能做3-4个的重量),但往往到最后一两次时会用不上力气了,此时在保护下坚持的再做一两次是整个训练过程中效果最好的阶段。总之,想要健身效果...
篮球高手请帮忙,不要复制粘贴,请用你们的话来指点我一下。
篮球高手请帮忙,不要复制粘贴,请用你们的话来指点我一下。 我今年16岁,14岁时开始打球,可我的技术还是不见长啊,以前打的很勤,有时天天打,有时隔几天,最近是1周打1,2次。我的最大烦恼就是今天打的好,明天打的坏,今天能得20分,明天就得... 我今年16岁,14岁时开始打球,可我的技术还是不见长啊,以前打...
请各位高手指点下,深圳市农民工医疗保险和住院保险的区别,还有就是报销...
1、社保中医保分三种,(农民工)合作医疗、住院医疗、综合医疗。提醒你的是,综合医疗的企业缴费比例比较大,最低工资标准2175,你自己交200,公司交400左右,没有强制给非深户购买。企业有权不给你买。2、看病有两种可能,平时的门诊和住院(手术)3、(农民工)合作医疗看门诊都是按照比例报销的,...
电脑总是蓝屏,平均一小时一次,请高手指点下~~错误代码如下~如果有效...
2 如果只是运行个别软件或游戏偶尔出现的,重启电脑再试,或到其他地方下载其他版本的软件重新安装。3 点 开始菜单 运行 输入 cmd 回车,在命令提示符下输入 for %1 in (%windir%\\system32\\*.dll) do regsvr32.exe \/s %1 然后 回车。然后让他运行完,应该就可能解决。4 最近电脑中毒、安装了...
成语高手请帮忙指点下,++分
成语高手请帮忙指点下,++分 求一些带“yi”字的成语,只要音对了就行,是哪个yi字都无所谓的。是词就行,也不一定要是成语,比如(依)依不舍,清爽(宜)人。有没有高人帮帮忙。越多越好。... 求一些带“yi”字的成语,只要音对了就行,是哪个yi字都无所谓的。是词就行,也不一定要是成语,比如(依)依不舍...
《很急》刚买的笔记本出现问题,开机出现加载时出错,请高手指点下...
【注意】如果启动项没有的话,请接着用下面软件解决的方法 IceSword 1.22 中文版 下载地址 http:\/\/www.onlinedown.net\/soft\/53325.htm 打开IceSword.exe,点左下角的“文件”,在目录"+"找到加载时出错的文件所在文件夹,加载时出错的文件上键点“强制删除”。【注意】:启动项并不一定指向特定的...
请高手指点下,本人想玩诛仙青云。怎么加点和加天书
矛盾在于一个2S释放一个6S释放,个人认为真正的混战中青云的所有群攻技能只是给自爆收下尾扫扫地,况且5重里有太极玄天真诀也是2S释放,攻击更是不弱,如此多的群攻技能,可真正能在混战中全部使用的到吗?我想没那么多时间给你挨个去用吧。那就强化某1个或2个,所以我选天地不仁,虽然是6S释放,...
GHOST的问题 请高手指点下
系统瘫痪进不了系统,开机按键盘F8进安全模式--选正常启动—回车--进“请选择要启动的操作系统”--使用方向键↓选择“WIN XP”下边的“一键GHOST...”选项—选“一键恢复”)—点选“恢复”-确定。4、重新备份系统 开始--程序--一键GHOST,打开“一键GHOST” 对话框—点选“一键备份C盘”--选“...
我想要学电吉他,请高手指点下新手应该注意些什么,还有就是给我些建 ...
说到学习吉他,首先是左右手的配合,可以从爬格子开始,不要图快,可以从慢速开始,但是要开着节拍器,速度不是最重要的,最重要的是左右手的配合和节拍的准确还有弹琴身体和手的姿势一定要正确,如果一开始没有养成良好的习惯,等将来再改,是非常非常困难的.之后就可以练习一下手指的独立性,这个是很重要的,...
我是会计新手,请高手指点一下
没有做过会计工作,刚刚到一家新公司做会计,营业执照在2010年12月24号就拿到了,税务登记证,组织机构代码证(所有副本)那些都拿到了,基本户在1月中旬开了,现在还没去报过税,所有财务上的东西也没有买,还在开基本户时有一些费用,我2月24日上班后应该要做些什么呢,财务室只有我一个人,请各位指点一下,越详细...
穆图杏香: 基类A定义了一个虚函数 virtual void fun(),那么编译器在编译的时候,自动会为类A生成一个名叫“__vfptr”的成员常量指针,是一个函数指针,排在类成员的最前面.这个函数指针指向类A对应的虚函数表(vftable),该虚函数表存储了A::...
积石山保安族东乡族撒拉族自治县19282841231: 简述多态的概念,多态实现的条件,c++问题 - ?
穆图杏香: 多态(Polymorphism)按字面的意思就是"多种状态".在面向对象语言中,接口的多种不同的实现方式即为多态.引用Charlie Calverts对多态的描述--多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对...
积石山保安族东乡族撒拉族自治县19282841231: c++多态问题 - ?
穆图杏香: 一个事物可以从各个角度去诠释.一张白纸可以被认为是:白颜色的物体,纸,可折叠物,可燃物,等等…… 白颜色的物体,纸,可折叠物,可燃物这些在C++里就是类.一个对象同时可以作为多个类的实例来访问的性质就是这个对象的多态性.
积石山保安族东乡族撒拉族自治县19282841231: 什么叫多态?在c++中如何实现多态 - ?
穆图杏香: 多态是面向对象的基本特征之一. 而虚函数是实现多态的方法. 简单的说,建立一个父类的对象,它的内容可以是这个父类的,也可以是它的子类的,当子类拥有和父类同样的函数,当使用这个对象调用这个函数的时候,定义这个对象的类(也就是父类)里的同名函数将被调用,当在父类里的这个函数前加virtual关键字,那么子类的同名函数将被调用.
积石山保安族东乡族撒拉族自治县19282841231: 什么叫做多态性 ?在C++中是如何实现多态的? - ?
穆图杏香: C++中的多态(虽然多态不是C++所特有的,但是C++中的多态确实是很特殊的)分为静多态和动多态(也就是静态绑定和动态绑定两种现象),静动的区别主要在于这种绑定发生在编译期还是运行期,发生在编译期的是静态绑定,也就是静多...
积石山保安族东乡族撒拉族自治县19282841231: 什么是多态?在C++中多态是如何实现的? - ?
穆图杏香: 多态性是指一段程序能够处理多种对象的能力.在c++语言中可以通过强制多态,重载多态,类型参数化多态,包含多态4种形式来实现..希望采纳
积石山保安族东乡族撒拉族自治县19282841231: 使用C++的多态性解决问题需要注意什么,容易碰上什么问题 - ?
穆图杏香: 多态一般分为两种,一种是复写,一种是重载,1:复写:函数名相同,列参合返回值都一样,但是里面实现的功能可能不一样,这个一般是子类复写父类里面的方法2:重载,函数名相同,但参数列表不一样 其实我觉得应该注意的是:向上转型和向下转型1:向上转型,在提高代码复用性有很好的体现,但是只能实现父类里面的方法2:向下转型,一般用在获取特定的子类对象
积石山保安族东乡族撒拉族自治县19282841231: 请说明C++的多态是何种机制?简单说明就好,谢谢 - ?
穆图杏香: 简单点说就是“一个对外接口,多个内在实现” 在C++中,多态性分为两种,一种称为编译时多态,另一种为运行时多态 分别解释下:1.编译时多态,也就是函数重载,所谓函数重载是指同一个函数名可以对应着多个函数的实现,具体调用哪个按照由参数个数,参数类型等来决定,这个简单,就不说了2.运行时多态,就是虚函数. 在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,以实现你所想要的功能.
积石山保安族东乡族撒拉族自治县19282841231: 一个关于C++多态性的问题 - ?
穆图杏香: 多态性(polymorphism)是面向对象编程的基本特征之一.而在C++中,多态性通过虚函数(virtual function)来实现.我们来看一段简单的代码:#include <iostream> using namespace std; class Base { int a; public:virtual void fun1() {cout<<"...
积石山保安族东乡族撒拉族自治县19282841231: 请教C++高手!关于多态的一个问题?
穆图杏香: 方法1是正确的,而方法2是错误的. Item_base *base = &Bulk_item(100, 0.3, 40);这是方法2中定义并初始化base指针的语句,Bulk_item(100, 0.3, 40)这是调用Bulk_item类的构造函数初始化一个Bulk_item类的临时对象,所以base指向的是一...