1.继承类时需要注意的地方
(1)当一个类作为基类的时候,这个类就必须有定义。
(2)在派生类中,基类的默认构造函数可以被隐式调用,但是如果基类的构造函数都有参数,派生类需要直接调用一个。派生类的构造函数只能描述派生类自己的成员变量和自己的基类的直接初始式,它不能直接初始化基类的成员。
Manager::Manager(const string &n, int d, int lvl) :family_name(n), //错误:在Manager里没有family_name声明 department(d), //错我:在Mangager里没有department声明 level(lvl){ //... } //错误:没有调用Employee的构造函数
(3)类对象的构造是自下而上的:首先是基类,再是成员,最后是派生类本身。类对象的销毁是自上而下的:首先是派生类本身,而后是成员,最后是基类。
(4)当某个virtual函数是inline的,那么就可以用“::”特殊说明的调用使用在线替换。使我们能处理一些情况,例如某个虚函数针对同一个对象调用了另一个虚函数。
(5)抽象类。最重要的用途是提供一个界面,而不暴露任何实现细节。不过,一个未在派生类里定义的纯虚函数仍然是纯虚函数,这样派生类仍然是一个抽象类。
2.从实例中体会类的继承。
(1)我们先看一看我们传统的继承类的方式:
//Ival_box能从某个用户界面取得一个整数 class Ival_box{ protected: int val; int low,high; bool changed; public: Ival_box(int ll, int hh){ changed = false; val = low = ll; high = hh; } virtual int get_value(){ changed = false; return val; } virtual void set_value(int i){ changed = true; val = i; } virtual void reset_value(int i){ changed = false; val = i; } virtual void prompt{} virtual bool was_changed()const{ return changed;} };
class Ival_slider:public Ival_box{ //定义滑块的视觉图形要素等 //...public: Ival_slider(int, int); int get_value(); void prompt(); };
(2)假设我们实现图形要素需要一个叫“BBWindow”的类,我们就得重写Ival_box类,让Ival_box类继承BBWindow类。但是假如我们还需要BJWindow类,ZXWindow类等多个类呢,我们不可能让Ival_box类全部继承一遍。所以,C++之父给出了一个对我比较有启示的继承方式,类层次结构相当清晰:
//用户界面应该是一个实现细节,对于希望了解它的用户应该是隐蔽的 //类Ival_box应该不包含数据 //在用户界面修改后,无需重新编译使用Ival_box的一族类的代码 //针对不同界面的Ival_box能在我们的程序中共存。 class Ival_box{ public: virtual int get_value() = 0; virtual void set_value(int i) = 0; virtual void reset_value(int i) = 0; virtual void prompt() = 0; virtual bool was_changed() const = 0; virtual ~Ival_box(); };
完整的层次结构是将我们面向应用的概念层次结构当做界面组成,用派生类表示:
class Ival_box{/*...*/} class Ival_slider: public Ival_box{/*...*/} class Ival_dial: public Ival_box{/*...*/} class Flashing_ival_slider: public Ival_slider{/*...*/} class Popup_ival_dial: public Ival_dial{/*...*/}
接下来的这一层次结构针对的是各种图形用户界面的实现,也表示为派生类:
class BBslider:public BBWindow{/*...*/}; class CWslider:public CWWindow{/*...*/}; class BB_ival_slider: public Ival_slider, protected BBsilder{/*...*/}; class BB_flashing_ival_slider:public Flashing_ival_slider, protected BBWindow_with_bells_and_whistles{/*...*/}; class BB_popup_ival_slider:public Popup_ival_slider, protected BBslider{/*...*/}; class CW_ival_slider:public Ival_slider, protected CWslider {/*...*/};
这个类的层次结构是这样的:
最后在继承类的时候,我们可以运用到以下的建议:数据成员最好是私用的,这可以使派生类无法来干扰它们。更进一步的说,数据应该放在派生类中,在派生类中,我们可以根据具体需要确切的定义数据,又不会把无关的派生类弄乱,对于几乎所有情况,保护界面只应该包含函数,类型和常量。