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

  • 表面上直接了当的public继承概念,是由两部分组成的:函数接口继承和函数实现继承;
    考虑一个如下绘图程序代码:
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 {//...};

首先考虑纯虚函数draw,纯虚函数有连个突出特性:1:他们必须被任何"继承了它们"的具象class 重新声明,2:通常他们在抽象class中通常没有定义;
我们也可以为纯虚函数提供定义,但是调用它的唯一途径是"调用时指出其class 名称":

Shape *ps = new Shape; //错误,Shapre是抽象类
Shape *ps1 = new Rectangle;
ps1->draw();		  //调用Rectangle::draw

Shape *ps2 = new Ellipse;
ps2->draw();		  //调用Ellipse::draw

ps1->Shape::draw();   // 调用Share::draw
ps2->Shape::draw();   // 调用Share::draw
  • 声明简朴的(非纯)impure virtual函数的目的,是让derived classed继承该函数的接口和缺省实现.但是,允许impure virtual函数同时指定函数声明和函数缺省行为,却有可能造成危险,考虑如下代码:
class Airport {//...}; //表示机场
class Airplane {
public:
	virtual void fly(const Airport &destionation);
	//...
};

void Airplane::fly(const Airport &destionation) {
	//缺省代码,将飞机飞行至指定目的地
}
class ModelA : public Airplane {};
class ModelB : public Airplane {};

为了表示所有飞机都一定能飞,并阐明"不同飞机原则上需要不同的fly实现"fly被声名为virtual,它同时被ModelA和ModelB继承

现在决定购买新飞机C,它和A,B的飞行方式不同,由于急着上线,忘记了重新定义fly函数

class ModelC : public Airplane {
};

然后代码中有这样的行为:

Airport PDX(...) //PDX
Airplane *pa = new ModelC;
//...
pa->fly(PDX)

上述代码将酿成大难,程序试图以ModelA和ModelB的飞行方式来飞ModelC,有一种做法是切断"virtual 函数接口"和其"缺省实现"之间的连接,如下:

class Airplane {
public:
	virtual void fly(const Airport &destionation) = 0;
	//...
protected:
	void defaultFly(const Airport &destionation)	;
};

void Airplane::defaultFly(const Airport& destionation) {
	// 缺省行为
}

fly被改为一个pure virtual函数,只提供飞行接口.若想使用缺省实现(例如ModelA和ModelB),可以在其fly函数中对defaultFly做一个inline调用:

class ModelA : public Airplane {
public:
	virtual void fly(const Airport & destionation) {
		defaultFly(destionation);
	}
};

class ModelB : public Airplane {
public:
	virtual void fly(const Airport & destionation) {
		defaultFly(destionation);
	}
};

现在ModleC class不可能意外继承不正确的fly实现代码,因为Airplane中的pure virtual函数迫使ModelC必须提供自己的fly版本

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

void ModelC::fly(const Airport &destionation) {
// C型飞机行为
}

最后让我们看看Shape的non-virtual函数objectID

class Shape {
public:
	int objectID() const;
	//...
};
  • 声明non-virtual函数的目的是为了令derived classes继承函数接口及一份强制性实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值