C/C++编程:绝不重新定义继承而来的缺省参数值

1060 篇文章 307 订阅

原因

让我们一开始就将讨论简化。你只能继承两种函数,virtual和non-virtual函数。然而重新定义一个继承而来的non-virtual函数永远是错误的。我们可以安全的将本条款的讨论局限于”继承一个带有缺省参数的virtual函数“。

这种情况下,本条例成立的理由就十分明确了:virtual函数是动态绑定,而缺省参数值是静态绑定。

解释

对象的所谓静态类型,就在程序中被声明时所采用的类型。看个例子:

class Shape{
public:
	enum ShapeColor{Red, Green, Blue};
	virtual void draw(ShapeColor color=Red) const = 0;
};

class Rectangle : public Shape{
public:
	//糟糕! 这里赋予了不同的缺省值
	virtual void draw(ShapeColor color=Green) 
};

class Circle : public Shape{
public:
	virtual void draw(ShapeColor color) const = 0;
	// 注意:上面这么写则当客户以对象调用此函数,一定要指定参数值
	//   因为静态绑定下这个函数并不从其Base继承缺省参数值
	//   但是如果以指针或引用调用此函数,可以不执行参数值
	//   因为动态绑定下这个函数会从其基类继承缺省参数值
}

在这里插入图片描述
现在考虑这些指针:

Shape *ps ;                // 静态类型为Shape*
Shape *pc = new Circle;    // 静态类型为Shape*
Shape *pr = new Rectangle ; // 静态类型为Shape*

对象的所谓动态类型则是值目前所指对象的类型。也就是说,动态类型可以表现出一个对象将有什么行为。以上面为例,ps没有动态类型,因为它尚未指向任何对象;pc的动态类型时Circle*, ps的动态类型时Rectangle *

动态类型如名所示,可以在程序执行过程中改变(通过通过赋值)

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(Shape::Red);

上面的预期缺省值应该是GREEN,但是由于pr的静态类型是Shape*,所以此时调用的缺省参数值是Shape class的而不是Rectangle class的。

引用所面对的问题和指针一样。重点在于draw是个虚函数,而它有个缺省参数在派生类中被重新定义了。

为什么C++坚持以这种方式运作呢?答案在于运行期效率。如果缺省参数是动态绑定,编译器就必须有某种方法在运行期为虚函数决定适当的参数缺省值。这会造成效率低下而且实现复杂。

那么如果你遵守这条规则,并且同时提供缺省值给基类和派生类,又会发生什么呢?

class Shape{
public:
	enum ShapeColor{Red, Green, Blue};
	virtual void draw(ShapeColor color=Red) const = 0;
};

class Rectangle : public Shape{
public:
	virtual void draw(ShapeColor color=Red) 
};

这很糟糕:代码重复,而且如果Shape内的缺省参数改变了,那些派生类也要跟着改。怎么办呢?

当你想让虚函数表现出你想要的行为却遭遇麻烦,这时候C/C++编程:考虑虚函数以外的其他选择 。比如NVI手法(模板方法模式):令基类的一个public non-virtual函数调用private virtual函数。这里我们可以让non-virtual函数指定缺省值参数,而private virtual函数负责真正的工作:

class Shape{
public:
	enum ShapeColor{Red, Green, Blue};
	void draw(ShapeColor color=Red){
		doDraw(color);
	}
private:
	virtual void doDraw(ShapeColor  color) const = 0;
};

class Rectangle : public Shape{
private:
	virtual void doDraw(ShapeColor color) const; 
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值