Effective C++ (E3 37)笔记之不重新指定继承而来的默认参数值

有个抽象类表示形状,其中纯虚函数draw有默认形参:

class shape{
public:
	enum shapecolor{Red,Green,Blue};
	virtual void draw(shapecolor col=Red) const=0;
	std::string retcol(shapecolor col) const{
		std::string str;
		switch(col)
		{
			case Red:
				str="Red";break;
			case Green:
				str="Green";break;
			case Blue:
				str="Blue";break;
			default:
				break;
		}
		return str;
	}
};
同时有两个继承类表示长方形和圆形,分别提供了带默认形参和不带默认形参的draw实现:

class rectangle:public shape{
public:
	virtual void draw(shapecolor col=Green) const{
		cout<<"rectangle::draw "<<retcol(col)<<endl;
	}
};

class circle:public shape{
public:
	virtual void draw(shapecolor col) const{	//when user call draw,para have to be set
		cout<<"circle::draw "<<retcol(col)<<endl;
	}
};
实例化对象后调用draw函数:

	rectangle rec;
	rec.draw();
	circle cir;
	cir.draw(shape::Blue);	//if no para,report err

	shape* ptr=new rectangle();
	ptr->draw();
	shape* ptr1=new circle();
	ptr1->draw();

结果为:


通过直接定义rectangle和circle的对象 调用draw(),获取到的默认参数前者是Green而后者为空,必须指定否则报错。说明 静态绑定下,默认参数即为 rectangle和circle声明时的样子,无法从base类继承

而通过base指针调用rectangle和circle对象的draw(),获取到的默认参数却都是Red。这说明默认参数是静态绑定的,由于指针是base类型,故编译期就已决定是base的默认参数,尽管调用哪个virtual函数时动态绑定的。于是导致了base类和derived类各出一半力的怪异结果。

由此可见绝不应该重新定义继承而来的参数值。那么derived类该如何指定默认形参呢?

也指定为Red?那会导致代码重复而且会对base类产生依赖。即base类一旦改变参数值derived也得跟着改。

较好方法是使用NVI手段将draw函数移到private,并提供一个public non-virtual 函数(外覆器)调用真正干活的函数dodraw:

class shape{
public:
	enum shapecolor{Red,Green,Blue};
	void draw(shapecolor col=Red) const{
		dodraw(col);
	}
	std::string retcol(shapecolor col) const{
		std::string str;
		switch(col)
		{
			case Red:
				str="Red";break;
			case Green:
				str="Green";break;
			case Blue:
				str="Blue";break;
			default:
				break;
		}
		return str;
	}
private:
	virtual void dodraw(shapecolor col) const=0;
};

class rectangle:public shape{
private:
	virtual void dodraw(shapecolor col) const{
		cout<<"rectangle::draw "<<retcol(col)<<endl;
	}
};

class circle:public shape{
private:
	virtual void dodraw(shapecolor col) const{
		cout<<"circle::draw "<<retcol(col)<<endl;
	}
};
可见 通过NVI手法仅在外覆器指定默认参数,因为non-virtual本来就不该被重新定义,否则属于名称覆盖和多态没关系了。 当然derived类也就不指定默认参数了。现在调用完全符合预期:

	rectangle rec;
	rec.draw();

	circle cir;
	shape* ptr=○
	ptr->draw();
	ptr->draw(shape::Green);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值