阿龙的学习笔记---Effective C++---第六章:继承与面向对象设计
-
条款32:确定你的public继承出is-a关系
-
公开继承public inheritance代表一种is-a关系,D是B的继承,那么B是一种更一般化的概念,而D是一种特殊化的概念。B可以实现的,D一定可以实现,这才是is-a关系。
-
比如square正方形与rectangle矩形之间的关系,在数学上来说,正方形就是一种矩阵。但是假如在面向对象中表示呢?
假如rectangle可以随意改变长和宽的函数,square继承之后可以使用吗?答案是否定的。
-
所以public继承关系的原则就是:适用于base-class的每一个方法一定要适用于derived-class。
-
-
条款33:避免遮掩继承而来的名称
-
例如有一个global变量int x,函数内又定义了一个int x,那么在函数内出现x时,编译器会找到函数内定义的这个,这就对global的变量造成了遮掩。
-
在函数继承中同样会有这个问题,以函数为例(其他也是一样,只讨论名称):
class Base { public: virtual void mf1(); virtual void mf1(int); virtual void mf2(); void mf3(); void mf3(int); void mf4(); }; class Derived: public Base { public: virtual void mf1(); virtual void mf2(); void mf3(); }; Derived d; int x; d.mf1(); //调用Drived::mf1(); d.mf1(x); //调用失败Base中的mf1(int)被Drived::mf1()函数隐藏。 d.mf2(); //调用Drived::mf2(); d.mf3(); //调用Drived::mf3(); d.mf3(x); //调用失败Base中的mf3(int)被Drived::mf3()函数隐藏。 d.mf4(); //调用Base::mf4();
比如这个例子中,mf1、mf2、mf3都在派生类中重新声明,无论是不是virtual函数。重载的函数也并没有继承下来。
-
如果想使用base中的同名函数,可以使用using声明:
class Derived: public Base{ public: //让Base class内名为mf1和mf3的所有东西在Derived作用域内都可见,且为public using Base::mf1; using Base::mf3; virtual void mf1(); void mf3(); void mf4(); }; int x; d.mf1();//调用Drived::mf1(); d.mf1(x);//调用Base中的mf1(int)。 d.mf2();//调用Drived::mf2(); d.mf3();//调用Drived::mf3(); d.mf3(x);//调用Base中的mf3(int)。 d.mf4();//调用Base::mf4();
-
如果并不想使用base中的所有同名函数,那么可以写一个转交函数(forwarding function)
class Derived: public Base{ public: virtual void mf1(int x) { base::mf1(x); } }; Derived d; d.mf1(5); //正确 d.mf(); //错误
-
-
条款34:区分 接口继承 和 实现继承
-
接口继承和实现继承是说:在派生类中,你希望只继承某个函数的接口声明;还是希望能够继承接口和实现,并且也可以覆写;或者只希望继承接口和声明但不能覆写。 这就有三种做法。
-
1、pure-virtual纯虚函数的目的就是让派生类只继承函数接口,在所有的派生类中必须要再手动实现,拥有pure-virtual函数也会让base类成为一个抽象类,不能够创建实体,只为了继承。
-
2、impure-virtual函数让derived-class继承了函数接口以及缺省实现,派生类中可以使用继承而来的实现,也可以重写自己特殊的实现。
但这种做法也可能会有漏洞,可能会使得派生类忘记重写而造成不好的影响。
一种做法是将virtual函数接口和缺省函数实现分开,virtual函数接口被声明为pure-virtual函数,而缺省函数实现作为base类中的一个protected非虚函数。如果要使用缺省行为时,则直接调用那个缺省函数实现。
另一种做法相似,但更简单。由于pure-virtual函数也可以定义,虽然不会被缺省继承,但是可以在派生类中调用。只需要在前面加上base类的名称限定符。
-
3、non-virtual函数用来继承一个函数接口并接收强制性实现,不可以重写(除非被名称隐藏,类似上一条)
-
下一篇: 挤出来的人生