Effective C++条款34:区分接口继承和实现继承

考虑以下类:

class Shape
{
public:
	virtual void draw() const = 0;
	virtual void error(const std::string & msg);
	int objectID() const;
	...
};
class Rectangle : public Shape{...};
class Ellipse : public Shape {...};

Shape是一个抽象类,它的纯虚函数draw使它成为一个抽象类.所以客户不能创建Shape class的实体。Shape class声明了三个函数,首先考虑纯虚函数draw:

	virtual void draw() const = 0;

由于是纯虚函数,派生类必须重新声明也就是说派生类必须提供一个draw函数,不管你怎么实现它。
但是我们也可以给纯虚函数提供定义,调用它的时候明确指出其class名称:

Shape * p = new Rectangle;
p->Shape::draw();

一般而言这个性质用途有限,我们可以使用非纯虚函数提供更平常和更安全的默认实现,比如error:

	virtual void error(const std::string & msg);

这个接口表示,每个类都必须支持一个当遇上错误时可调用的函数,也就是说,你必须支持一个error函数,但如果你不想写,可使用基类的默认版本.

但是允许非纯虚函数同时指定函数声明和函数默认行为,有可能造成危险。考虑以下的类:

class Airport{...};
class Airplane
{
public:
	virtual void fly(const Airport & destination);
	...
};
class ModelA : public Airplane{...};
class ModelBpublic Airplane{...};

现在假设又有了一个新式的C型飞机。但它们的飞行方式不同。程序员在继承体系中针对C型飞机添加了一个类,但由于他们急着让新飞机上线服务,竟然忘了重新定义fly函数:

class ModelC:public Airplane{...};

然后代码中有以下的动作:

Airplane * p = new ModelC;
p->fly(...);

这是一个大问题,这个程序试图以ModelA或ModelB的飞行方式来飞ModelC。
解决这个问题的办法是:切断虚函数接口和默认实现之间的连接,把fly声明为纯虚函数.

	virtual void fly(const Airport & destination) = 0protected:
		void defaultFly(...);

fly以及被改为纯虚函数,只提供飞行接口。若想要使用默认实现,可以在fly函数中对defaultFly做一个inline调用.

有些人反对以不同的函数分别提供接口和默认实现,像上面的flydefaultFly那样。这个矛盾这么解决呢?
解决办法也很简单:

	virtual void fly(const Airport & destination) = 0void Airplane::fly(const Airport & destination)
	{
		...
	}

我们为纯虚函数提供一个实现,用纯虚函数替换了独立函数defaultFly.

总结:

1.接口继承和实现继承不同,在public继承下,派生类总是继承基类的接口.
2.纯虚函数只具体指定接口继承.
3.非纯虚函数具体指定接口和默认实现继承.
4.非虚函数具体指定接口继承和强制性实现继承.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值