条款36、绝不重新定义继承而来的缺省参数值

	为简化问题,只定义两种函数:虚函数和非虚函数。从前面我们知道重定义继承而来的非虚函数是错误的。所以我们讨论“继承一个带有缺省参数值的虚函数”。
	理由十分明确:1、虚函数是动态绑定   2、缺省参数值是静态绑定

对象的静态类型,即在程序中声明时所采用的类型。考虑以下:
class Shape
{
   public:
   enum ShapeColor{Red,Green,Blue};
   virtural void draw(ShapeColor color=Red) const=0;//所有形状必须提供一函数用于描绘自己
…..
};
class Rectangle:public Shape
{
public:
   //重新定义缺省函数值,错误设计
   virtual void draw(ShapeColor color=Green) const;
….
};
class Circle: public Shape
{
         public:
virtual void draw(ShapeColor color) const;
//上述这么写则当客户以对象调用此函数则一定要指定参数值
//因为静态绑定下并不从Base继承缺省参数值
//如果以指针或引用调用,则可不指定,因为动态绑定下该函数会从基类继承缺省参数值
}

考虑这些指针:
Shape* ps;      //静态类型为Shape*
Shape* pc=new circle; //静态类型为Shape*
Shape* pr=new rectangle;  //静态类型为Shape*

上述三指针都是声明为指向Shape的类型,所以都以它们为静态类型,无论真正指向什么,它们静态类型都为Shape*
动态类型则是指:目前所指对象的类型。动态类型可以表现一个对象将会有什么行为。如上,pc动态类型为circle*…ps则没有动态类型。
动态类型可以在执行中改变,如:
ps=pc;   //ps当前动态类型是Circle*
ps=pr;   // ps当前动态类型是Rectangle*

虚函数由动态绑定而来,意思是调用虚函数时究竟执行哪一实现代码,取决于调用的那个对象的动态类型。如:
	pc->draw(Shape::red);      //Circle:: draw(Shape::red)
	pr->draw(Shape::red);     //Rectangle:; draw(Shape::red)

但考虑如下调用:
	pr->draw();

	很明显,调用的是Rectangle的draw函数,但因为pr静态类型为Shape*。所以调用的来缺省参数来自于Shape类而非Rectangle.即预期是Green,而实际参数是Red。这样奇怪的调用,由Shape和Rectangle类的draw声明式各出一半力。

	即使把指针换为引用,结果还是一样。重点是:draw是个虚函数,但它有个缺省参数在派生类被重定义了。
为何c+坚持这种方式动作?答案是运行效率。如果缺省参数值是动态绑定,编译器必须有某方法在运行时决定适当的参数缺省值,这比在“编译时期”决定复杂很多。

如果依照上面规则,同时定义基类和派生类缺省参数会怎样?如下;
class Shape
{
         public:
enum ShapeColor{Red,Green,Blue};
virtural void draw(ShapeColor color=Red) const=0;//所有形状必须提供一函数用于描绘自己
…..
};
class Rectangle:public Shape
{
public:
         virtualvoid draw(ShapeColor color=Red) const;
….
};

这样的代码重复且具有相依性,如果基类缺省参数改变,则所有派生类也必须改变,否则还是会导致“重新定义一个继承而来的缺省参数值”
解决的方法是考虑替代设计,如NVI。非虚函数指定缺省参数,private虚函数真正工作;
class Shape
{
         public:
enum ShapeColor{Red,Green,Blue};
void draw(ShapeColor color=Red) const
{
         doDraw(color);
}
private:
virtual void doDraw(ShapeColor color) const=0;  //真正完成处理工作
};
class Rectangle:public Shape
{
private:
         virtualvoid doDraw(ShapeColor color=Red) const; //不需要指定缺省参数值
….
};

因为非虚函数绝对不会被重写,这个设计使得draw函数的缺省参数值总为Red

需要记住的:
	1、绝不重新定义一个继承而来的缺省参数值,因为缺省参数值是静态绑定。而唯一应该覆写的虚函数,却是动态绑定。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值