- 表面上直接了当的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
继承函数接口及一份强制性实现