Inheritance and Object-Oriented Design #
32.Make sure public inheritance models “is-a” #
public inheritance(公开继承)意味"is-a"(是一种)的关系
33.Avoid hideing inherited names #
derived classed 内的名称会遮掩base classed内的名称
class Base{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
void mf3();
void mf3(double);
}
class Derived : public Base{
public:
virtual void mf1();
void mf3();
void mf4();
}
Derived d;
int x;
...
d.mf1();
d.mf1(x);//错误
d.mf2();
d.mf3();
d.mf3(x);//错误,因为Derived::mf3遮掩了一个名为Base::mf3但是类型不同的Base函数
下面使用using解决上面的问题
class Base{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
void mf3();
void mf3(double);
}
class Derived : public Base{
public:
using Base::mf1;//让Base class内名为mf1和mf3的所有东西
using Base::mf3;//在Derived 作用域内都可以(并且public)
virtual void mf1();
void mf3();
void mf4();
}
Derived d;
int x;
...
d.mf1();
d.mf1(x);//正常
d.mf2();
d.mf3();
d.mf3(x);//正常
using声明式会令继承而来的某给定名称之所有同名函数在derived class中都可见
class Base{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
}
//Derived唯一想继承的mf1是那个无参数版本,通过转交函数实现
class Derived : privata Base{
public:
virtual void mf1()//转交函数(forwarding function)
{
Base::mf1();
}
void mf3();
void mf4();
}
Derived d;
int x;
...
d.mf1();
d.mf1(x);//正常
34.Differentiate between inheritance of interface and inheritance of implementation #
-
声明pure virtual函数的目的是为了让derived classed 只继承函数接口
-
声明impure virtual函数的目的是为了让derived classed继承该函数的接口和缺省实现
-
声明non-virtual函数的目的是为了让derived classed继承函数的接口及一份强制性实现
class Airplane{ public: virtual void fly(const Airport& destination) = 0; ... protected: void defaultFly(const Airport& destination); }; void Airplane::defaultFly(const Airport& destination) { //缺省行为 } 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); } ... };
35.Consider alternatives to virtual functions #
-
藉由Non-Virtual Interface手法实现Template Method模式
class GameCharacter{ public: int healthValue() const { ... int retVal = doHealthValue(); ... return retVal; } private: virtual int doHealthValue() const //derived classes可重新定义 { ... } }
令客户通过public non-virtual成员函数间接调用private virtual函数,称为non-virtual interface(NVI)手法,把这个non-virtual函数(healthValue)称为virtual函数的外覆器(wrapper)
-
藉由Function Pointers实现Strategy模式
class GameCharacter; int defaultHealthCalc(const GameCharacter& gc); class GameCharacter{ public: typedef int (*HealthCalcFunc)(const GameCharacter&); explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc):healthFunc(hcf) { } int healthValue() const { return healthFunc(*this); } private: HealthCalcFunc healthFunc; } class EvilBadGuy: public GameCharacter{ public: explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc):GameCharacter(hcf) { ... } ... }; int loseHealthQuickly(const GameCharacter&); int loseHealthSlowly(const GameCharacter&); EvilBadGuy ebg1(loseHealthQuickly); EvilBadGuy ebg2(loseHealthSlowly);
古典的strategy模式
class GameCharacter; class HealthCalcFunc{ public: virtual int calc(const GameCharacter& gc) const { ... } }; HealthCalcFunc defaultHealthCalc; class GameCharacter{ public: explict GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalc):pHealthCalc(phcf) {} int healthValue() const { return pHealthCalc->calc(*this); } private: HealthCalcFunc* pHealthCalc; };
36.Never redefine an inherited non-virtual function #
声明了virtual函数是动态绑定的(dynamically bound)
class B{
public:
void mf();
...
};
class D:public B{
public:
void mf();
...
};
D x;
B* pB = &x;
pB->mf();//调用B::mf
D* pD = &x;
pD->mf();//调用D::mf
- 绝对不要重新定义继承而来的non-virtual函数
37.Never redefine a function’s inherited default parameter value #
缺省参数值是静态绑定的。如果缺省参数值是动态绑定的,编译器就必须有某种办法在运行期为virtual函数决定适当的参数缺省值,为了运行期效率和编译器实现上的简易度,C++做了取舍。
class Shape{
public:
enum ShapeColor{Red,Green,Blue};
virtual void draw(ShapeColor color = Red) const = 0;
};
class Rectangle:public Shape{
public:
virtual void draw(ShapeColor color = Green) const;
};
class Circle:public Shape{
public:
virtual void draw(ShapeColor color) const;
};
Shape* ps;
Shape* pc = new Circle;
Shape* pr = new Rectangle;
pr->draw();//调用Rectangle::draw(Shape::Red);
可以参考条款35中NVI(non-virtual interface)手法:令base class内的一个public non-virtual函数调用private virtual 函数,后者可被derived classes重新定义
class Shape{
public:
enum ShapeColor{Red,Green,Blue};
void draw(ShapeColor color = Red) //这样设计可以保证draw方法的默认参数总为Red
{
doDraw(color);
}
private:
virtual void doDraw(ShapeColor color) const = 0;
};
class Rectangle:public Shape{
public:
...
private:
virtual void doDraw(ShapeColor color) const;
};
38.Model “has-a” or “is-implemented-in-terms-of” through composition #
复合(composition)意味着有一个(has-a)或者根据某物实现出(is-implemented-in-terms-of)
在应用域(application domain),复合意味has-a(有一个),在实现域(implementation domain)复合意味is-implemented-in-terms-of(根据某物实现出)
39.Use private inheritance judiciously #
如果classes之间的继承关系是private,编译器不会自动将一个derived class对象(例如Student)转换为一个base class对象(例如Person)
由private base class继承而来的所有成员,在derived class中都会变成private属性,纵使它们在base class 中原本是protected或public属性
复合和private继承都意味is-implemented-in-terms-of,无论什么时候,只要可以,你还是应该选择复合
40.Use multiple inheritance judiciously #
virtual继承会增加大小、速度、初始化复杂度等等成本
尽量不要使用多继承