条款32 确定你的public继承塑模出is-a关系
不用怀疑,public inheritance(公开继承)意味“is-a”(是一种)的关系。也就是说,如果令class D('Derived') 以public形式继承class B('Base'),即每一个类型为D的对象同时也是一个类型为B的对象。反之不成立。
所以在进行面向对象类设计时,需要明确继承之前是否是"is-a"关系,以决定derived类与base类设计的合理性。
举例说明,
class Person{...}; class Student:public Person{...}; void eat(const Person& p);//任何人都会吃饭 void study(const Student& s);//只有学生才到学校学习 Person p; Student s; eat(p);//OK,p是人 eat(s);//OK,s是学生,也是人 study(s);//学生进校学习 //以下调用存在生活常识错误 study(p);//错误,不一定所有人都进校学习当使用public继承时,必须时刻注意不要违背这一层关系 ,如有需要,可将错误限制在编译期内,或在运行期内提示错误(没有前一点好),见下举例,
class Bird { public: virtual void fly();//鸟可以飞 }; class Penguin:public Bird{//企鹅是一种鸟 };企鹅是一种鸟,没错。但利用public继承是"is-a"关系,就不对啦。因为企鹅不会飞。于是这样定义继承关系就出现明显的逻辑漏洞。将此错误限制在编译期内的做法,
class Bird { //此处不声明fly函数 }; class FlyingBird :public Bird { public: virtual void fly(); }; class Penguin :public Bird {//企鹅是一种鸟 //没有声明fly函数 };或者在运行期内提示错误,
void error(const string& msg); class Penguin :public Bird {//企鹅是一种鸟 public: virtual void fly() { error("Attempt to make a penguin fly!"); } };is-a并非是唯一存在于classes之间的关系,另两个常见的关系是has-a(有一个,见条款38、39)和is-implemented-in-terms-of(根据某物实现出,见条款38、39)。
条款33 避免遮掩继承而来的名称
此条款需要明确了两点重要知识,其一,是类内使用using声明式,其二,名字在作用域内查找规则。
有如下基类以及派生类,及图片说明其作用域范围,
class Base { private: int x; public: virtual void mf1() = 0; virtual void mf2(); void mf3(); }; class Derived :public Base { public: virtual void mf1();//存在覆盖基类函数现象,但具有虚函数特性 void mf4(); };
针对derived class内的mf4的实现码,
void Derived::mf4() { mf2(); }上述mf2函数,遵循的查找作用域顺序规则: 本函数内->所属派生类->所属基类->内含Base的namespace->global作用域 。
以下是存在遮掩继承而来的名称,
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();//存在覆盖基类函数现象,但具有虚函数特性 void mf3();//具有遮掩base内的同名函数效果 void mf4(); }; Derived d; int x; d.mf1();//OK d.mf1(x);//error!因为Derived::mf1遮掩了Base::mf1 d.mf2();//OK d.mf3();//OK d.mf3(x);//error!因为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的所有东西在Derived作用域内都可见 using Base::mf3; virtual void mf1();//存在覆盖基类函数现象,但具有虚函数特性 void mf3();//具有遮掩base内的同名函数效果 void mf4(); }; Derived d; int x; d.mf1();//OK d.mf1(x);//OK,可以调用Base::mf1 d.mf2();//OK d.mf3();//OK d.mf3(x);//OK,可以调用Base::mf3
以上内容均来自Scott Meyers大师所著Effective C++ version3,如有错误地方,欢迎指正!相互学习,促进!!