条款32:确定你的public继承塑模出is-a模型
class D(derived)以public形式继承class B(base),则每一个类型为D的对象同时也是一个类型为B的对象,反之不成立,因此B比D表现出更加一般化的概念,而D比B表现出更特殊化的概念。在C++领域里面,任何函数如果希望获得一个类型为B的实参,都也愿意接受一个类型为D的对象,这就是is-a(是一种)的关系;代码分享:
class ractangle{
public:
virtual void setheight(int newheight);
virtual void setwidth(int newwidth);
virtual int height( ) const;
virtual int width( ) const;
};
void makebigger(rectangle &r){
int oldheight=r.height( );
r.setwidth(r.width( )+10);
assert(r.height()==oldheight);//assert为真
}
class square:public rectangle{ ...};
square s;
assert(s.width()==s.height( ));//assert为真
makebiggle(s);
assert(s.width()==s.height( ));//asseert为真 ,为什么s没有发生变化;
在本例分析中,某些可施行在矩形身上的事情(宽度可独立于高度被修改)却没办法施行在正方形身上(宽度和高度一样),但public主张,能够施行在base class对象上的每一件事情,都能施行于derived class对象上,所以正方形和矩形的例子中不满足is-a模型;pulic就意味着is-a模型,因此在继承中确定你的class之间的关系,并合理塑造它们;
条款33:避免遮掩继承而来的名称(继承而导致的作用域问题)
在public继承中,derived class中的成员函数会将base class中重名的成员函数覆盖掉,从而出现因继承导致成员函数调用问题;因此使用public继承但又不继承那些重载函数,这就违背了public继承中的is-a原则;
如果你想继承base class并加上重载函数,而你希望重新定义或者复写其中一部分,那么你必须为那些原本会被遮掩的每个名称引用一个using的声明,否则某些你希望继承的名称会被遮掩;
如果derived以private方式继承的base,如果使用using声明,那么给定名称的函数会在derived中都可见,这并不是我们希望达到的目的,这时候我们可以使用一个简单的转交函数;
class base{
public:
virtual void mf1()=0;
virtual void mf1(int);
...
};
class derived:private base {
public:
virtual void mf1( ){//转交函数
base::mf1( );//inline函数
}
};
条款34:区分接口继承和实现继承
public继承分为函数接口继承和函数实现继承;
1)对于pure virtual函数,它有两个特性,它们必须被任何“继承了它们”的具象class重新声明,而且它们在抽象class中通常没有定义,因此声明一个pure virtual函数的目的是为了derived class只继承接口(只具体接口继承);
引申:我们可以给pure virtual函数提供定义,也就是说你可以给base中的pure virtual函数提供一份实现代码,C++并不会发出警告和错误,但调用它的唯一途径就是:调用时明确指出其class路径;(一直以为pure virtual函数不能在base内实现)
2)derived class继承函数接口,但是impure virtual函数会提供一份实现代码,derived class可能会赋写它;声明简朴的impure virtual 函数的目的,是让derived classes继承该函数的接口和缺省实现(具体指定接口继承和缺省实现继承);
如果在继承过程中,derived class中没有重新定义virtual class,那么就默认使用base class中的virtual函数;如果两个class都共享着一份相同的性质,可以把这份相同的性质搬到base class中,从而避免代码重复,这是典型的面向对象的设计方法;
3)对于一个non-virtual函数,意味着它并不打算在derived class中有不同的行为,实际上一个non-virtual成员函数所表现出来的不变性凌驾其特异性,因此不管derived class变得多特异化,它的行为都不可以被改变;声明一个non-virtual函数的目的是为了令derived class继承函数的接口及一份强制性的实现(具体指定接口及强制性实现继承);