标签:des style blog color 使用 2014
(一)
class Shape {
public:
virtual void draw() const = 0;
virtual void error(const string& msg);
int objectID() const;
};
class Rectangle : public Shape {...};
class Ellipse : public Shape {...};
公有继承的概念看似简单,似乎很轻易就浮出水面,然而仔细审度之后,我们会发现公有继承的概念实际上包含两个相互独立的部分:函数接口的继承和函数实现的继承。二者之间的差别恰与函数声明和函数实现之间相异之处等价。成员函数的接口总是被继承,因为public继承意味is-a。
pure virtual 函数两个突出特征:(1)必须被任何“继承了它们”的具象class重新声明;(2)它们在抽象class中通常没有定义。
(二)
声明一个pure virtual函数的目的是为了让derived class只继承函数接口。我可以为它提供一份实现代码,但调用它的唯一途径是“调用时明确指出期class的名称”。
Sharp* ps1 = new Rectangle; ps1->draw(); Sharp* ps2 = new Rectangle; ps2->draw(); ps1->Shape::draw();//调用Shape的draw ps2->Shape::draw();(三)
声明impure
virtual函数的目的,是让derived classes继承该函数的接口和缺省实现。
允许impure
virtual函数同时指定函数声明和函数缺省行为,却有可能造成危险。
class Airport {...};
class Airplane {
public:
virtual void fly(const Airport& destination);
};
void Airplane::fly(const Airport& destination) {
//缺省代码,将飞机飞至指定目的地
}
class ModelA : public Airplane {...};
class ModelB : public Airplane {...};
class ModelC : public Airplane {
...//未声明fly函数,但它并不希望缺省飞行
};
Airport PDX(...);
Airplane* pa = new ModelC;
...
pa->fly(PDX); //未说出“我要的情况下就继承了该缺省行为,酿成大灾难”这个程序试图用ModelA和ModelB的飞行方式来飞ModelC。解决办法(1):此间伎俩在于切断“virtual
函数接口”和其“缺省实现”之间的连接。下面是一种做法:
class Airplane {
public:
virtual void fly(const Airport& destination) = 0;
...
protected:
void defaultFly(const Airport& destination);
};
void Airplane::defaultFly(const Airport& destination) {
//缺省行为,将飞机飞至目的地
}fly已被改成为一个pure
virtual函数,只提供飞行接口。缺省行为以defaultFly出现在Airplane class中。若想使用缺省实现(例如ModelA和ModelB),可以在fly中对defaultFly做一个inline调用:
class ModelA: public Airplane {
public:
virtual void fly(const Airport& destination) {
defaultFly(destination);
}
...
};
class ModelB: public Airplane {
public:
virtual void fly(const Airport& destination) {
defaultFly(destination);
}
...
};现在ModelC不可能意外继承不正确的fly实现代码了,因为Airplane中的pure
virtual函数迫使ModelC必须提供自己的fly版本:
class ModelC: public Airplane {
public:
virtual void fly(const Airport& destination);
...
};
void ModelC::fly(const Airport& destination) {
//将C型飞机飞至指定的目的地
}像这样的话,这个方案并非安全无虞,程序员还是可能因为剪贴(copy-and-paste)代码而招来麻烦,但它比原来的设计值得依赖。解决办法(2):
我们可以利用“pure
virtual函数必须在derived class中重新声明,但它们可以拥有自己的实现”这一事实。下面是Airplane继承体系如何给pure virtual函数一份定义:
class Airplane {
public:
virtual void fly(const Airport& destination) = 0;
...
};
void Airplane::fly(const Airport& destination) // pure virtual 函数实现 {
//缺省行为,将飞机飞至指定目的地
}
class ModelA: public Airplane {
public:
virtual void fly(const Airport& destination) {
Airplane::fly(destination);
}
};
class ModelB: public Airplane {
public:
virtual void fly(const Airport& destination) {
Airplane::fly(destination);
}
};
class ModelC: public Airplane {
public:
virtual void fly(const Airport& destination)
...
};
void ModelC::fly(const Airport& destination) {
// 将C型飞机飞至指定目的地
}
声明non-virtual函数的目的是为了令derived
class继承函数的接口及一份强制性实现。
class Shape {
public:
...
int objectID() const;
}; 来看Shape::objectID的声明:可以想做是“每个Shape对象都有一个用来产生对象识别码的函数:此识别码总是采用相同计算方法,该方法由Shape::objectID的定义式决定,任何derived
class都不应该尝试改变其行为”。
请记住:
1. 接口继承&实现继承不同。在public继承之下,derived classes总是继承base class的接口。
2. Pure virtual函数只具体指定接口继承。
3. Impure virtual函数具体指定接口继承及缺省实现继承。
4. non-virtual函数具体指定接口继承以及强制性实现继承。
Effective C++:条款34:区分接口继承和实现继承,布布扣,bubuko.com
Effective C++:条款34:区分接口继承和实现继承
标签:des style blog color 使用 2014
原文地址:http://blog.csdn.net/u010470972/article/details/35558685