条款32 确保你的public继承塑模出is-a关系
记住:
★public继承意味着is-a。适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个derived class对象也都是一个base class对象。
条款33 避免遮掩继承而来的名称
记住:
★derived classes内的名称会遮掩base classes内的名称。在public继承下从来无人希望如此
★为了让被遮掩的名称再见天日,可使用using声明式或转交函数
-------------------------------------------------------------
编译器看到某个名称,其做法是逐层向外围查找各作用域。
-----------------------------
举个例子:
class Base { private: int x; public: virtual void mf1() = 0; virtual void mf1( int ); virtual void mf2(); void mf3(); void mf3( double ); ... }; class Derived : public Base { public: virtual void mf1(); //遮掩base的同名函数 void mf3(); //遮掩base的同名函数 void mf4(); ... }; Derived d; int x; ... d.mf1(); //正确,调用Derived::mf1 d.mf1(x); //错!因为Derived::mf1遮掩Base::mf1 d.mf2(); //正确,调用Base::mf2 d.mf3(); //正确,调用Derived::mf3 d.mf3(x); //错!因为Derived::mf3遮掩Base::mf3
解决办法:使用using声明式
class Base { private: int x; public: virtual void mf1() = 0; virtual void mf1( int ); virtual void mf2(); 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(); //仍正确,调用Derived::mf1 d.mf1(x); //没问题了!调用Base::mf1 d.mf2(); //仍正确,调用Base::mf2 d.mf3(); //仍正确,调用Derived::mf3 d.mf3(x); //没问题了!调用Base::mf3
-----------------
有时并不想继承base classes的所有函数,这是可以理解的。但这在public继承下绝不可能发生,∵其违反了public继承所暗示的is-a关系。
例如,Derived以private形式继承Base,而唯一想继承的mf1是无参版。using声明式技术此时就不行了,∵using声明式会令继承而来的某给定名称之所有同名函数在derived class中都可见。
此时需要“转交函数”技术:
class Base { public: virtual void mf1() = 0; //仅想继承这个 virtual void mf1( int ); ... }; class Derived : private Base { //注意是以private方式继承!!!而非public public: //???有点不能理解 virtual void mf1() { //此为转交函数,暗自inline Base::mf1(); } ... }; Derived d; int x; ... d.mf1(); //正确,调用Derived::mf1(本质是里面调用Base版!!!) d.mf1(x); //错误!Base::mf1(int)被遮掩了,同时这也达到目的 //∵我们的目的就是唯一想继承的mf1是无参版
条款34 区分接口继承和实现继承
记住:
★接口继承和实现继承不同。在public继承下,derived classes总是继承base class的接口
★纯虚函数只具体指定接口继承
★普通虚函数具体指定接口继承及缺省实现继承
★非虚函数具体指定接口继承以及强制性实现继承
------------------------------------------------
一种特殊情形:
基类的纯虚函数必须在derived classes中重新声明,且基类的纯虚函数在基类中也是可以给出详细定义的,这个定义也可以表现出一种缺省行为(那是derived class可能使用的,但只有在它们明确提出申请时才是)。
class Airplane { public: virtual void fly( const Airport &destination ) = 0; //纯虚! ... }; void Airplane::fly( const Airport &destination ) { //基类纯虚函数竟也可以提供定义!!! //缺省行为 } class ModelA : public Airplane { public: virtual void fly( const Airport &destination ) { Airplane::fly( destination ); //derived class须明确提出申请!!! } ... }; class ModelB : public Airplane { public: virtual void fly( const Airport &destination ) { Airplane::fly( destination ); //derived class须明确提出申请!!! } ... }; class ModelC : public Airplane { public: virtual void fly( const Airport &destination ); //ModelC自己重新定义 ... }; void ModelC::fly( const Airport &destination ) { //属于C类型飞机自己特有的飞行方式 }