======================继承而来的非虚函数======================
假设类Derive公有继承自类Base,且类Base定义了一个公有非虚成员函数func:
class Base
{
public:
void Func();
...
};
class Derive : public Base
{
...
}
Derive de; //定义一个派生类对象
Base *pb = &de; //得到一个指向de的Base指针
pb->Func(); //通过指针调用Func()
Derive *pd = &de; //得到一个指向de的Derive指针
pd->Func(); //通过指针调用Func()
这种情况下,如果Derive没有重新定义Func函数时,两个指针调用Func的行为是相同的;但是,如果Func是非虚函数且Derive又重新定义了自己的Func版本,那么两者的行为就不会相同了:
class Derive : public Base
{
public:
void Func(); //隐藏了Base::Func;
...
};
pb->Func(); //调用Base::Func()
pd->Func(); //调用Derive::Func()
这种行为的两面性原因在于:Base::Func()和Derive::Func()这样的非虚函数是静态绑定的。因此,即使pb指向的是从Base派生的类的对象,但由于pb被声明为执行Base的指针类型,所以通过pb调用非虚函数时就总是调用那些定义在类Base中的函数。
与之相反,虚函数是动态绑定的,不会存在上述问题。通过pb或pd调用Func()时都将导致调用Derive::Func(),因为pb和pd实际上都是指向类型Derive的对象。
结论:如果写派生类Derive时重新定义从基类Base继承而来的非虚函数Func(),Derive的对象就可能表现出精神分裂的症状。引用也会和指针一样表现出这种异常行为。
因此,任何情况下都要禁止重新定义继承而来的非虚函数。
======================继承而来的缺省参数值=====================
重定义缺省参数值的唯一方法是重定义一个继承而来的函数,而由上面分析可知,重定义继承而来的非虚函数是错误的,因此,我们这里主要讨论“继承一个有缺省参数值的虚函数”。
虚函数是动态绑定的而缺省参数值是静态绑定的。
对象的静态类型是指我们声明的存在于程序代码文本中的类型:
enum ASCEShapeColor{RED, GREEN, BLUE};
class ASCEShape //基类
{
public:
//所有形状都要提供这样一个函数绘制自身
virtual void draw(ASCEShapeColor color=RED) const = 0;
...
};
class ASCERectangle : public ASCEShape
{
public:
//定义了不同的缺省参数值错误!
virtual void draw(ASCEShapeColor color = GREEN) const;
...
};
class ASCECircle : public ASCEShape
{
public:
virtual void draw(ASCEShapeColor color) const;
...
};
ASCEShape *ps; //静态类型是ASCEShape*
ASCEShape *pr = new ASCEShapeRectangle; // 静态类型是ASCEShape*
ASCEShape *pc = new ASCEShapeCircle; //静态类型是ASCEShape*
上面三个指针的静态类型和它们实际所指向的对象的类型是没有关系的。
而对象的动态类型是由它当前所指的对象的类型决定的,即对象的动态类型表示它将执行何种行为。如上面的代码中,pr的动态类型是ASCERectangle*,pc的动态类型是ASCECircle*,而ps实际上没有动态类型,因为它还没有指向任何对象。
动态类型可以在程序运行时改变,典型的方法是通过赋值:
ps = pr; //ps的动态类型现在是ASCERectangle*
ps = pc; //ps的动态类型现在是ASCECircle*
虚函数就是动态绑定的,即虚函数通过哪个对象被调用,具体被调用的函数就由那个对象的动态类型决定:
pr->draw(REG); //调用ASCERectangle::draw(REG)
pc->draw(REG); //调用ASCECircle::draw(REG)
虚函数机制的正确性是毋庸置疑的,但当将虚函数和缺省参数值结合起来分析就会产生问题:虚函数是动态绑定的,但缺省参数是静态绑定的,这意味着我们最终可能调用的是一个定义在派生类,但使用了基类中的缺省参数值的虚函数:
pr->draw(); //调用的是ASCERectangle::draw(REG)!!,而不是ASCERectangle::draw(GREEN)
由此,结论就是:禁止重新定义继承而来的缺省参数值!!
分享到:
相关推荐
电子教案-《自我管理》(第一单元第二课+认清自身角色)-4.pdf
做好规划认清自我让自己不再是SEO“流浪者”-文档资料.pdf做好规划认清自我让自己不再是SEO“流浪者”-文档资料.pdf做好规划认清自我让自己不再是SEO“流浪者”-文档资料.pdf做好规划认清自我让自己不再是SEO“流浪...
做好规划认清自我让自己不再是SEO“流浪者”-文档资料.ppt做好规划认清自我让自己不再是SEO“流浪者”-文档资料.ppt做好规划认清自我让自己不再是SEO“流浪者”-文档资料.ppt做好规划认清自我让自己不再是SEO“流浪...
九年级政治认清基本国情测试题-初中三年级政治试题练习、期中期末试卷-初中政治试卷.pdf
上海市中考政治 认清基本国情复习教案-人教版初中九年级全册政治教案.doc
教育精品资料
中考政治 九年级 第二单元 第三课 认清基本国情复习教案-人教版初中九年级全册政治教案.doc
2022长春继续教育认清历史使命,用于责任担当-简答题答案归纳.pdf
认清“增根”和“无解”.pdf认清“增根”和“无解”.pdf认清“增根”和“无解”.pdf认清“增根”和“无解”.pdf认清“增根”和“无解”.pdf
建筑钢结构工程技术-认清分包、转包、内包、挂靠.docx
在迎新典礼上的讲话-《认清现实,提高自我》.doc
九年级思想品德教案-第三课《认清基本国情》
顶级投行、金融估值建模培训资料-认清所处周期,把握动态变化.pdf
认清自己.exe
和上一次公布版本新增设:: 1.删除新闻发布的上传组件,因为一些杀毒软件误报,以免给大家带来误会! 2.删除一些无法访问的网站,导入新收录的一些新站! 3.后台添加网址时加入网站LOGO,站长QQ等信息! 4.LOGIN.asp提交...
认清基本国情.ppt
九年级政治全册 第三课 认清基本国情导学与测评 新人教版-新人教版初中九年级全册政治学案.doc
认清基本国情1.ppt
认清疾病的本质.doc