
c程序设计基础第八章继承和派生.ppt
106页C++程序程序设计基基础第第8章章 继承与派生承与派生北京北京邮电大学信通院大学信通院方莉方莉第第8 8章章 继承与派生承与派生v类具有具有封装性、封装性、继承性和多承性和多态性性,使得,使得软件开件开发者可以把者可以把类设计成相成相对独立的模独立的模块,像一个个,像一个个积木木块,便于重用便于重用v类的的继承性承性是是实现软件重用件重用的一种重要形式的一种重要形式v本章将学本章将学习::§继承和派生的概念,承和派生的概念,继承方式;承方式;§派生派生类的构造函数和析构函数;的构造函数和析构函数;2第第8 8章章 继承与派生承与派生8.1 8.1 继承的概念承的概念8.2 8.2 定定义基基类和派生和派生类8.3 8.3 构造函数和析构函数构造函数和析构函数8.4 8.4 转换与与继承承38.1 8.1 继承的概念承的概念- -例子例子自行自行车Bicycle山地山地车 Mountain Bike竞速自行速自行车 Racing Bike双人自行双人自行车 Tandem Bike48.1 8.1 继承的概念承的概念- -例子例子v山地山地车继承承了自行了自行车的特征的特征山地山地车 ““派生派生””于于 自行自行车58.1 8.1 继承的概念承的概念 v类的的继承承是在是在现有有类的基的基础之上,之上,创建新建新类的机制的机制。
称称现有的有的类为基基类,,新建立的新建立的类为派生派生类§派生派生类继承了基承了基类的属性和行的属性和行为§派生派生类是基是基类的特殊情况的特殊情况v基基类是是共性的抽象共性的抽象,派生,派生类是是个性的体个性的体现v不必从不必从““草稿草稿””开始开始创建特殊的程序建特殊的程序对象v继承是承是处理理““特殊情况特殊情况””的面向的面向对象象编程机制 6Bike基类Tandem Bike派生类派生于int Wheel;bool Run();int Wheel;bool Run();int Seat;父类子类 从基类继承8.1 8.1 继承的概念承的概念 7第第8 8章章 继承与派生承与派生8.1 8.1 继承的概念承的概念8.2 8.2 定定义基基类和派生和派生类8.3 8.3 构造函数和析构函数构造函数和析构函数8.4 8.4 转换与与继承承88.2 8.2 定定义基基类和派生和派生类v定定义派生派生类时要声明要声明继承方式承方式,三种,三种继承方式:承方式:§publicpublic§ProtectedProtected§private private v访问控制受控制受继承方式的影响;承方式的影响;v不同不同继承方式的影响主要体承方式的影响主要体现在:在: §派生派生类成成员对基基类成成员的的访问控制;控制; §派生派生类对象象对基基类成成员的的访问控制;控制;v继承承导致一种特殊的致一种特殊的语法法现象:象:同名覆盖同名覆盖。
98.2.1 8.2.1 简单的的继承和派生承和派生v问题:想在屏幕上画出正三角形、矩形或:想在屏幕上画出正三角形、矩形或圆形形v方法一:方法一:结构化方法构化方法§DrawTri (int x, int y, char color, int side);DrawTri (int x, int y, char color, int side);§DrawRect (int x, int y, char color, int length, int width)DrawRect (int x, int y, char color, int length, int width)§DrawCircle(int x, int y, char color, int Radius)DrawCircle(int x, int y, char color, int Radius)v方法二:面向方法二:面向对象?象?§class circle class circle 圆形形§class rectangle class rectangle 矩形矩形§class triangle class triangle 三角形三角形§基基类:: class shapeclass shape•色彩色彩 colorcolor•位置位置 (x, y)(x, y)shapecirclerectangletriangle泛化?10v图形形§circle circle 圆形形§rectangle rectangle 矩形矩形§triangle triangle 三角形三角形 基基类称称为父父类派生派生类称称为子子类 shapecirclerectangletrianglev分分层次的次的设计类使模使模块划分更合划分更合理;便于理;便于软件系件系统的的设计和和维护。
8.2.1 8.2.1 简单的的继承和派生承和派生11class Shape{private: int m_x,m_y; //位置位置 char m_color; //颜色色public: Shape(); void setposition(int x, int y); void setcolor(char color); int getx(); int gety(); char getcolor();};例例1-1-定定义基基类shapeshape成成员函数的分函数的分类::1.构造函数构造函数2.设置属性置属性值3.读取属性取属性值12class Triangle: public Shape {public:Triangle(int x, int y, char color='R', float slen = 1);float GetSideLength() const;void SetTriangle(int x, int y, char color, float slen);void Draw();private:float m_SideLength;};例例1-1-定定义派生派生类( (等等边三角形三角形类) )成成员函数的分函数的分类::1.构造函数构造函数2.设置属性置属性值3.读取属性取属性值13派生派生类的定的定义格式格式class class 派生派生类名:名:继承方式承方式 基基类名名{ { public: public: // //派生派生类公有成公有成员…… private:private: // //派生派生类私有成私有成员…… } }派生派生类只有只有一个直接基一个直接基类为单继承承8.2.2 8.2.2 定定义派生派生类14 class 派生派生类名:名:继承方式承方式 基基类名名1, … 继承方式承方式 基基类名名n { public: //派生派生类公有成公有成员… private: //派生派生类私有成私有成员… }有多个基有多个基类派生派生类有有多个基多个基类为多多继承承8.2.2 8.2.2 定定义派生派生类15u例如例如: : 已有基已有基类b1b1和和b2b2,,定定义派生派生类derivederive,其中包括:,其中包括:u私有整型成私有整型成员 newIntnewInt,,u公有函数成公有函数成员 intint newFunnewFun()(),,u私有函数成私有函数成员 intint max(intmax(int a, a, intint b) b);;u写出写出类derivederive的定的定义8.2.2 8.2.2 定定义派生派生类class derive : public b1 , private b2{private: int newInt;public: void newFun();private:int max( int a, int b );};16v类的的继承方式是承方式是派生派生类对基基类成成员的的继承方式承方式。
v类的的继承承方方式式影影响响类外外模模块对于于派派生生类从从基基类继承承来来的的成成员的的访问权限限v每一个每一个“继承方式承方式”,只用于限制,只用于限制对紧随其后随其后之基之基类的的继承class derive : public b1 , private b2{private: int newInt;public: void newFun();private:int max( int a, int b );};8.2.2 8.2.2 定定义派生派生类17class base{…… };class deriver1:public base{ …… };class deriver2:public deriver1{…… }•父父类被称被称为子子类的的直直接基接基类 •父父类的父的父类或更高或更高层次的父次的父类被称被称为这个个子子类的的间接基接基类 8.2.2 8.2.2 定定义派生派生类18class Shape:{public:Shape(int x=0, int y=0, char c = 'R');int GetX() const;void SetX( int x);int GetY() const;void SetY( int x);char GetColor() const;void SetColor(char c);protected:char m_color;int m_x;int m_y; };例例2-2-图形形类及其派生及其派生类的声明的声明19class Circle : public Shape {public:Circle(int x, int y, float r=1, char color='R');void SetCircle(int x, int y, float r, char color); float GetRadius () const; void Draw();private:float m_Radius;};例例2-2-图形形类及其派生及其派生类的声明的声明20class Triangle: public Shape {public:Triangle(int x, int y, char color='R', float slen = 1);void SetTriangle(int x, int y, char color, float slen);float GetSideLength() const; void Draw();private:float m_SideLength;};例例2-2-图形形类及其派生及其派生类的声明的声明21class Rectangle: public Shape{public:Rectangle(int x, int y, char color, int length=10, int width=10);void SetRectangle (int x, int y, char color, int length, int width); int GetWidth() const;int GetHeight() const;void Draw();private:int m_Width;int m_Length;};例例2-2-图形形类及其派生及其派生类的声明的声明22•派生派生类的成的成员包括:(包括:(1 1))继承基承基类的成的成员,(,(2 2)派生)派生类定定义时声声明的成明的成员。
•派生派生类自己增加的成自己增加的成员,完成两个,完成两个需求:需求:(1)(1)修改基修改基类成成员,(,(2 2)描)描述新的特征或方法述新的特征或方法 m_color;m_x; m_y;GetX();SetX();GetY();SetY();GetColor();SetColor();m_Radius;GetRadius () SetCircle();Draw(); 从基从基类继承的承的成成员派生派生类增加的增加的成成员238.2.3 8.2.3 访问控制和控制和继承关系承关系v类成成员的可的可见性性§公共成公共成员::publicpublic§保保护成成员::protectedprotected§私有成私有成员::privateprivatev继承的方式承的方式§公有公有继承承(public)(public)§保保护继承承(protected)(protected)§私有私有继承承(private)(private)v派生派生类继承了基承了基类中的所有成中的所有成员,,但不包括但不包括§构造函数构造函数§析构函数析构函数248.2.3 8.2.3 访问控制和控制和继承关系承关系v不同不同继承方式决定的不同承方式决定的不同访问控制控制权限体限体现在:在:§①①派生派生类的的成成员函数函数对其其继承的基承的基类成成员的的访问控制控制;;§②②其其它它模模块通通过派派生生类对象象对其其继承承的的基基类成成员的的访问控控制。
制private:protected:public:基类???派生类publicprotectedprivate继承方式决定继承成员的访问权限继承来的成员的访问权限?251. 1. 公有公有继承承 公有公有继承的派生承的派生类定定义形式:形式: class class 派生派生类名:名:publicpublic 基基类名名{ {派生派生类新成新成员定定义;;} }; ;private:protected:public:基类???派生类1.基基类成成员 在派生类中的访问属性不变2.派生派生类的成的成员函数函数 可以访问基类的公有成员和保护成员,不能访问基类的私有成员;3.派生派生类以外的其它函数以外的其它函数 可以通过派生类的对象,访问从基类继承的公有成员, 但不能访问从基类继承的保护成员和私有成员privateprotectedpublic派生类成员函数可以访问派生类对象基类成员的属性public26vpublicpublic是定是定义公有公有继承方式的关承方式的关键字v公有公有继承方式定承方式定义的派生的派生类,,继承了基承了基类中中除构造函数和析除构造函数和析构函数构函数外的其余成外的其余成员:公有成:公有成员、保、保护成成员和私有成和私有成员v被被继承的基承的基类成成员在派生在派生类中仍将中仍将保持保持其其原来的原来的访问属性属性。
v派生派生类的的成成员函数函数可以可以访问基基类的公有成的公有成员和保和保护成成员,,不不能能访问基基类的的私有成私有成员; ;v派生派生类以外的其它函数可以通以外的其它函数可以通过派生派生类的的对象,象,访问从基从基类继承的公有成承的公有成员, , 但但不能不能访问从基从基类继承的承的保保护成成员和私有和私有成成员 8.2.3 8.2.3 访问控制和控制和继承关系承关系27class Point//基基类Point类的定的定义{public://公有函数成公有函数成员void InitP(float xx=0, float yy=0) {X=xx;Y=yy;}void Move(float xOff, float yOff) {X+=xOff;Y+=yOff;}float GetX() {return X;}float GetY() {return Y;}private://私有数据成私有数据成员float X,Y;};8.2.3 8.2.3 访问控制和控制和继承关系承关系28class Rectangle: public Point//派生派生类声明部分声明部分{public://新增公有函数成新增公有函数成员void InitR(float x, float y, float w, float h){ InitP(x,y); //??访问基基类公有成公有成员函数函数 W=w;H=h;}float GetH() {return H;}float GetW() {return W;}private://新增私有数据成新增私有数据成员float W,H;};l派生派生类中的中的 成成员函函数数 可以直接可以直接访问基基类中的中的publicpublic和和protectedprotected成成员,但不,但不能能访问基基类的的privateprivate成成员。
8.2.3 8.2.3 访问控制和控制和继承关系承关系29main(){ Rectangle rect; cout< 8.2.3 8.2.3 访问控制和控制和继承关系承关系错误31class Point//基基类Point类的定的定义{public:void InitP(float xx=0, float yy=0) {X=xx;Y=yy;}void Move(float xOff, float yOff) {X+=xOff;Y+=yOff;}float GetX() {return X;}float GetY() {return Y;}protected:float X,Y;};8.2.3 8.2.3 访问控制和控制和继承关系承关系32class Rectangle: public Point//派生派生类声明部分声明部分{public://新增公有函数成新增公有函数成员void InitR(float x, float y, float w, float h){X=x; Y=y; //??访问基基类的保的保护成成员 W=w;H=h;}float GetH() {return H;}float GetW() {return W;}private://新增私有数据成新增私有数据成员float W,H;};l派生派生类中的中的 成成员函函数数 可以直接可以直接访问基基类中的中的public和和protected成成员,但不能,但不能访问基基类的的private成成员。 8.2.3 8.2.3 访问控制和控制和继承关系承关系正确正确33main(){ Rectangle rect; cout< privateprivateprivate派生类成员函数可以访问基类成员的属性private派生类对象35vprivateprivate是定是定义私有私有继承方式的关承方式的关键字字v以以私有私有继承方式承方式定定义的派生的派生类,,继承了基承了基类中可以中可以继承的成承的成员:公有成:公有成员、保、保护成成员和私有成和私有成员,,这些成些成员在派生在派生类中的中的访问属性都是属性都是私有的私有的v派生派生类的成的成员函数函数可以可以访问基基类的公有成的公有成员和保和保护成成员,,不不能能访问基基类的的私有成私有成员v派生派生类以外的其它函数以外的其它函数则不能不能通通过派生派生类的的对象象访问从基从基类继承的任何成承的任何成员 8.2.3 8.2.3 访问控制和控制和继承关系承关系36class Point { //基基类声明声明public: void InitP(float xx=0, float yy=0) {X=xx;Y=yy;} void Move(float xOff, float yOff) {X+=xOff;Y+=yOff;} float GetX() {return X;} float GetY() {return Y;}private: float X,Y;};8.2.3 8.2.3 访问控制和控制和继承关系承关系37class Rectangle: private Point//派生派生类声明声明{public://新增外部接口新增外部接口void InitR(float x, float y, float w, float h){InitP(x,y);W=w;H=h;}//?派生?派生类访问基基类公有成公有成员void Move(float xOff, float yOff) {Point::Move(xOff,yOff);}float GetX() {return Point::GetX();}float GetY() {return Point::GetY();}float GetH() {return H;}float GetW() {return W;}private://新增私有数据新增私有数据float W,H;};派生派生类中的中的 成成员函数函数 可以直接可以直接访问基基类中中的的publicpublic和和protectedprotected成成员,但,但不能不能访问基基类的的privateprivate成成员。 8.2.3 8.2.3 访问控制和控制和继承关系承关系正确正确38class Rectangle: private Point//派生派生类声明声明{public://新增外部接口新增外部接口void InitR(float x, float y, float w, float h) { X=x; Y=y;//? W=w;H=h; }void Move(float xOff, float yOff) {Point::Move(xOff,yOff);}float GetX() {return Point::GetX();}float GetY() {return Point::GetY();}float GetH() {return H;}float GetW() {return W;}private://新增私有数据新增私有数据float W,H;};派生派生类中的中的 成成员函数函数 可以直接可以直接访问基基类中的中的publicpublic和和protectedprotected成成员,,但不能但不能访问基基类的的privateprivate成成员。 8.2.3 8.2.3 访问控制和控制和继承关系承关系错误39class Point{//基基类声明声明public: void InitP(float xx=0, float yy=0) {X=xx;Y=yy;} void Move(float xOff, float yOff) {X+=xOff;Y+=yOff;} float GetX() {return X;} float GetY() {return Y;}protected: float X,Y;};8.2.3 8.2.3 访问控制和控制和继承关系承关系40class Rectangle: private Point//派生派生类声明声明{public://新增外部接口新增外部接口void InitR(float x, float y, float w, float h) { X=x; Y=y;//?? W=w;H=h; }void Move(float xOff, float yOff) {Point::Move(xOff,yOff);}float GetX() {return Point::GetX();}float GetY() {return Point::GetY();}float GetH() {return H;}float GetW() {return W;}private://新增私有数据新增私有数据float W,H;};8.2.3 8.2.3 访问控制和控制和继承关系承关系正确正确41main(){ Rectangle rect; cout< 8.2.3 8.2.3 访问控制和控制和继承关系承关系错误错误423. 3. 保保护继承承 保保护继承的派生承的派生类定定义形式:形式: class class 派生派生类名:名:protectedprotected 基基类名名{ {派生派生类新成新成员定定义;;} }; ;private:protected:public:基类???派生类1.基基类成成员::公有成公有成员和保和保护成成员在派生在派生类中中变成保成保护类型的,基型的,基类的私的私有成有成员属性不属性不变2.派生派生类的成的成员函数函数:可以可以访问基基类的公有成的公有成员和保和保护成成员,不能,不能访问基基类的私有成的私有成员;3.派生派生类以外的其它函数以外的其它函数:不能通不能通过派生派生类的的对象,象,访问从基从基类继承的任承的任何成何成员privateprotectedprotected派生类成员函数可以访问基类成员的属性prot-ected派生类对象43vprotectedprotected是定是定义保保护继承方式的关承方式的关键字字v以以保保护继承方式承方式定定义的派生的派生类,,继承了基承了基类中可以中可以继承的成承的成员:公有成:公有成员、保、保护成成员和私有成和私有成员。 其中基其中基类的的公有成公有成员和保和保护成成员在派生在派生类中中访问控制属性控制属性变成成保保护类型的型的,基,基类的的私有成私有成员保持保持原来属性原来属性v派生派生类的成的成员函数函数可以可以访问基基类的公有成的公有成员和保和保护成成员,,不不能能访问基基类的的私有成私有成员v派生派生类以外的其它函数以外的其它函数则不能不能通通过派生派生类的的对象象访问从基从基类继承的承的任何成任何成员 8.2.3 8.2.3 访问控制和控制和继承关系承关系44class Point { //基基类声明声明public: void InitP(float xx=0, float yy=0) {X=xx;Y=yy;} void Move(float xOff, float yOff) {X+=xOff;Y+=yOff;} float GetX() {return X;} float GetY() {return Y;}private: float X,Y;};8.2.3 8.2.3 访问控制和控制和继承关系承关系45class Rectangle: protected Point//派生派生类声明声明{public://新增外部接口新增外部接口void InitR(float x, float y, float w, float h){InitP(x,y);W=w;H=h;}//?派生派生类访问基基类公有成公有成员void Move(float xOff, float yOff) {Point::Move(xOff,yOff);}float GetX() {return Point::GetX();}float GetY() {return Point::GetY();}float GetH() {return H;}float GetW() {return W;}private://新增私有数据新增私有数据float W,H;};派生派生类中的中的 成成员函数函数 可以直接可以直接访问基基类中中的的publicpublic和和protectedprotected成成员,,但不能但不能访问基基类的的privateprivate成成员。 8.2.3 8.2.3 访问控制和控制和继承关系承关系正确正确46class Rectangle: protected Point //派生派生类声明声明{public: //新增外部接口新增外部接口void InitR(float x, float y, float w, float h) { X=x; Y=y;//? W=w;H=h; }void Move(float xOff, float yOff) {Point::Move(xOff,yOff);}float GetX() {return Point::GetX();}float GetY() {return Point::GetY();}float GetH() {return H;}float GetW() {return W;}private: //新增私有数据新增私有数据float W,H;};派生派生类中的中的 成成员函数函数 可以直接可以直接访问基基类中的中的publicpublic和和protectedprotected成成员,,但不能但不能访问基基类的的privateprivate成成员。 8.2.3 8.2.3 访问控制和控制和继承关系承关系错误47class Point { //基基类声明声明public: void InitP(float xx=0, float yy=0) {X=xx;Y=yy;} void Move(float xOff, float yOff) {X+=xOff;Y+=yOff;} float GetX() {return X;} float GetY() {return Y;}protected: float X,Y;};8.2.3 8.2.3 访问控制和控制和继承关系承关系48class Rectangle: protected Point //派生派生类声明声明{public: //新增外部接口新增外部接口void InitR(float x, float y, float w, float h) { X=x; Y=y;//?? W=w;H=h; }void Move(float xOff, float yOff) {Point::Move(xOff,yOff);}float GetX() {return Point::GetX();}float GetY() {return Point::GetY();}float GetH() {return H;}float GetW() {return W;}private: //新增私有数据新增私有数据float W,H;};派生派生类中的中的 成成员函数函数 可以直接可以直接访问基基类中的中的publicpublic和和protectedprotected成成员,,但不能但不能访问基基类的的privateprivate成成员。 8.2.3 8.2.3 访问控制和控制和继承关系承关系正确正确49main(){ Rectangle rect; cout< v在派生在派生类作用域内或者在作用域内或者在类外通外通过派生派生类的的对象直象直接使用接使用这个成个成员名,只能名,只能访问到派生到派生类中声明的同中声明的同名新成名新成员,,这个新成个新成员覆盖了从基覆盖了从基类继承的同名成承的同名成员,,这种情况称种情况称为同名覆盖同名覆盖 8.2.4 8.2.4 同名覆盖同名覆盖53class base {public: void f () {cout<<"base"< v同名覆盖同名覆盖55void main(){ deriver derobj; derobj.function();}输出出结果果:function of class deriver同名覆盖示例同名覆盖示例 56第第8 8章章 继承与派生承与派生8.1 8.1 继承的概念承的概念8.2 8.2 定定义基基类和派生和派生类8.3 8.3 构造函数和析构函数构造函数和析构函数8.4 8.4 转换与与继承承578.3 8.3 派生派生类构造函数和析构函数构造函数和析构函数v派派生生类继承承了了基基类中中除除构构造造函函数数和和析析构构函函数数之之外外的的所有成所有成员v基基类的构造函数和析构函数不能被派生的构造函数和析构函数不能被派生类所所继承承; ;v派生派生类一般需要定一般需要定义自己的构造函数和析构函数自己的构造函数和析构函数; ;v派生派生类的构造及析构函数通常会受到基的构造及析构函数通常会受到基类构造及析构造及析构函数的影响构函数的影响588.3.1 8.3.1 基基类只有只有无参数无参数的构造函数的构造函数v在基在基类具有具有无参构造函数无参构造函数,派生,派生类又又没有定没有定义构造构造函数函数的的时候,系候,系统会会自自动的的调用基用基类无参构造函数无参构造函数,,来构造派生来构造派生类对象中的基象中的基类成分。 成分59#include 63v如果基如果基类和和对象数据成象数据成员的的构造函数都无参数构造函数都无参数,,派生派生类构造函数构造函数形参表中将形参表中将只包含只包含用于初始化它用于初始化它自己的自己的基本基本类型数据成型数据成员的参数的参数v如果如果这个个派生派生类恰好恰好没有没有基本基本类型的数据成型的数据成员,,则其构造函数的形参表其构造函数的形参表为空,空,可以不定可以不定义构造函构造函数,而使用系数,而使用系统提供的默提供的默认构造函数构造函数 8.3.1 8.3.1 基基类只有无参数的构造函数只有无参数的构造函数648 8.3.3.2 .2 派生派生类的构造函数的构造函数v不参与不参与继承的特殊函数承的特殊函数§构造函数构造函数§析构函数析构函数§作作为特特权地位的友元函数地位的友元函数§赋值运算符函数运算符函数v派生派生类需要自己定需要自己定义的构造函数和析构函数的构造函数和析构函数65v基基类的构造函数不被的构造函数不被继承,需要在派生承,需要在派生类中自行定中自行定义 v派生派生类的构造函数完成:的构造函数完成:§初始化本初始化本类的数据成的数据成员;;§完成派生完成派生类中基中基类成分的初始化:通成分的初始化:通过调用基用基类的构造的构造函数,并函数,并为基基类的构造函数的构造函数传递参数;参数;§如果数据成如果数据成员有有对象,象,则需需调用用对象成象成员的构造函数;的构造函数;8 8.3.3.2 .2 派生派生类的构造函数的构造函数66v派生派生类的构造函数:的构造函数:§构造函数构造函数参数表参数表中以中以合适的初合适的初值为参数,初始化本参数,初始化本类中中新增成新增成员。 §利用利用成成员初始化表初始化表隐含含调用用基基类和和新增新增对象数据成象数据成员的的构造函数,初始化它构造函数,初始化它们各自的数据成各自的数据成员v构造函数的构造函数的调用次序用次序§系系统会使用会使用派生派生类构造函数的形参表的参数构造函数的形参表的参数调用用基基类和和内嵌内嵌对象成象成员的构造函数的构造函数 8 8.3.3.2 .2 派生派生类的构造函数的构造函数67v派生派生类构造函数的一般形式构造函数的一般形式: : 派派生生类名名::::派派生生类名名( (基基类所所需需的的形形参参,,本本类成成员所所需的形参需的形参) ): :基基类1(1(基基类参数表参数表1), …,1), …,基基类n(n(基基类参数表参数表n),n),对象象成成员1(1(对象象参参数数表表1), 1), …,…,对象象成成员m(m(对象象参参数数表表m)m){ { 本本类基本基本类型数据成型数据成员初始化;初始化;} } 8.3.2 8.3.2 派生派生类构造函数构造函数初始化列表68v单继承承时的构造函数的构造函数 派生派生类名名::::派生派生类名名( (基基类所需的形参,本所需的形参,本类成成员所需的形参所需的形参) ): :基基类名名( (参数参数) ){ { 本本类成成员初始化初始化赋值语句;句; } } 8.3.2 8.3.2 派生派生类构造函数构造函数69例例8-4 8-4 单继承派生承派生类构造函数构造函数70v多文件多文件结构:构:§主函数:主函数:ch8_4_main().cppch8_4_main().cpp§类TShapeTShape的声明:的声明:§类TShapeTShape的的实现::§类TEllipseTEllipse的声明:的声明:§类TEllipseTEllipse的的实现::例例8-4 8-4 单继承派生承派生类构造函数构造函数71#include "TShape04.h"#include "TShape04.h"#include 允色允许TShapeTShape的派生的派生类直接直接访问这些些颜色属性,而不允色属性,而不允许在在类外外通通过类的的对象直接象直接访问这些属性些属性 * */ / uchar _RED, _GREEN, _BLUE; uchar _RED, _GREEN, _BLUE;public:public: TShape(uint x, uint y);TShape(uint x, uint y); void getXY(uint& x, uint& y); void getXY(uint& x, uint& y); void setXY(uint x, uint y); void setXY(uint x, uint y); void Draw(); void Draw(); void getRGB(uchar& R, uchar& G, void getRGB(uchar& R, uchar& G, uchar& B);uchar& B); void setRGB(uchar R, uchar G, uchar void setRGB(uchar R, uchar G, uchar B);B);};};例例8-4 8-4 单继承派生承派生类构造函数构造函数72#include "TEllipse04.h"#include "TEllipse04.h"#include 程序包含包含内嵌内嵌对象象的派生的派生类构造函数构造函数76例例8-5 8-5 派生派生类的构造函数的构造函数77v多文件多文件结构:构:§主函数:主函数:ch8_5_main().cppch8_5_main().cpp§类TColorTColor的声明:的声明:§类TColorTColor的的实现:: §类TShapeTShape的声明:的声明:§类TShapeTShape的的实现::§类TEllipseTEllipse的声明:的声明:§类TEllipseTEllipse的的实现::§头文件文件例例8-5 8-5 派生派生类的构造函数的构造函数78#pragma once#pragma once#include "GlobalType05.h"#include "GlobalType05.h"#include "TColor05.h"#include "TColor05.h"class TShapeclass TShape{ {private:private: uint _x, _y; // uint _x, _y; //几何形状的位置几何形状的位置protected:protected: TColor _color; // TColor _color; //颜色色public:public: TShape(uint x, uint y);TShape(uint x, uint y); TShape(uint x, uint y, TColor color); TShape(uint x, uint y, TColor color); ~TShape(); ~TShape(); void getXY(uint& x, uint& y) const; void getXY(uint& x, uint& y) const; void setXY(uint x, uint y); void setXY(uint x, uint y); void Draw(); void Draw(); TColor getColor() const; TColor getColor() const; void setColor(TColor color); void setColor(TColor color);};};#pragma once //#pragma once //预处理指令,避免重复包含本理指令,避免重复包含本头文件文件typedef unsigned int uint;typedef unsigned int uint;typedef unsigned char uchar;typedef unsigned char uchar; #pragma once#pragma once#include "GlobalType05.h"#include "GlobalType05.h"enum EColorComponent {RED, GREEN, BLUE};enum EColorComponent {RED, GREEN, BLUE};class TColorclass TColor{ {private:private: uchar _RED, _GREEN, _BLUE; uchar _RED, _GREEN, _BLUE;public:public: TColor(const uchar R=0x00, const uchar TColor(const uchar R=0x00, const uchar G=0x00, G=0x00, const uchar B=0x00); const uchar B=0x00);////普通构造函数普通构造函数 TColor(const TColor& color); TColor(const TColor& color); ////拷拷贝构造函数构造函数 TColor& operator =(const TColor& color); TColor& operator =(const TColor& color);////重重载赋值运算符运算符 void setColor(uchar R, uchar G, uchar B); void setColor(uchar R, uchar G, uchar B); uchar getComponent(EColorComponent uchar getComponent(EColorComponent component) const;component) const;};};例例8-5 8-5 派生派生类的构造函数的构造函数79#include "TColor05.h"#include "TColor05.h"TColor::TColor(uchar R/* =0x00 */, TColor::TColor(uchar R/* =0x00 */, ////普通构造函数普通构造函数 uchar G/* =0x00 */, uchar G/* =0x00 */, uchar B/* =0x00 */){ uchar B/* =0x00 */){ _RED = R; _GREEN = G; _BLUE = B; _RED = R; _GREEN = G; _BLUE = B;} }TColor::TColor(const TColor& color){TColor::TColor(const TColor& color){////拷拷贝构构造函数造函数 _RED = color._RED; _RED = color._RED; _GREEN = color._GREEN; _GREEN = color._GREEN; _BLUE = color._BLUE; _BLUE = color._BLUE;} }void TColor::setColor(uchar R, uchar G, uchar B){void TColor::setColor(uchar R, uchar G, uchar B){ _RED = R; _GREEN = G; _BLUE = B; _RED = R; _GREEN = G; _BLUE = B;} }} }#pragma once#pragma once#include "TShape05.h"#include "TShape05.h"#include "GlobalType05.h"#include "GlobalType05.h"class TEllipse: public TShapeclass TEllipse: public TShape { {protected:protected: uint _longR, _shortR; uint _longR, _shortR;public:public: TEllipse(uint longR, uint TEllipse(uint longR, uint shortR, uint x, uint y, TColor shortR, uint x, uint y, TColor color);color); TEllipse(uint longR, uint TEllipse(uint longR, uint shortR, uint x, uint y);shortR, uint x, uint y); ~TEllipse(); ~TEllipse(); void Draw(); void Draw(); void getR(uint& longR, uint& void getR(uint& longR, uint& shortR) const;shortR) const; void setR(uint longR, uint void setR(uint longR, uint shortR);shortR);};};例例8-5 8-5 派生派生类的构造函数的构造函数80void TShape::getXY(uint& x, uint& y) void TShape::getXY(uint& x, uint& y) const{const{ x = _x; x = _x; y = _y; y = _y;} }void TShape::setXY(uint x, uint y){void TShape::setXY(uint x, uint y){ _x = x; _x = x; _y = y; _y = y;} }TColor TShape::getColor() constTColor TShape::getColor() const{ {return _color;return _color;} }void TShape::setColor(TColor color)void TShape::setColor(TColor color){ { _color=color; _color=color;} }#include "TShape05.h"#include "TShape05.h"#include "TColor05.h"#include "TColor05.h"#include 构造函数 85派生派生类的构造函数的构造函数v构造函数的构造函数的调用次序用次序1.基基类的构造函数的构造函数2.内嵌内嵌对象的构造函数象的构造函数3.派生派生类的构造函数的构造函数v因此因此§基基类 和和 内嵌内嵌对象象 的初始化的初始化只能放在初只能放在初始化列表中始化列表中,不能放到派生,不能放到派生类的构造函数体中的构造函数体中•多继承时,基类构造函数的调用顺序: 按照定按照定义派生派生类时这些基些基类被被继承的承的顺序序, 与他们在初始化列表的次序无关•派生类的多个对象成员的构造函数的调用顺序: 按照派生按照派生类定定义这些成些成员的的顺序序进行行, 与他们在初始化列表中的先后次序无关 有多个基有多个基类?? 多个内嵌多个内嵌对象?象?868.3.4 8.3.4 派生派生类的析构函数的析构函数 v派生派生类不能不能继承基承基类的析构函数的析构函数,需要,需要自己定自己定义析构函数,以便在派生析构函数,以便在派生类对象消亡之前象消亡之前进行必要行必要的清理工作。 的清理工作v派生派生类的析构函数只的析构函数只负责清理清理它它新定新定义的的非非对象象数据成数据成员,,对象数据成象数据成员由由对象成象成员所属所属类的析的析构函数构函数负责析构v析构函数的析构函数的调用次序与构造函数相反用次序与构造函数相反§先派生先派生类析构函数,再基析构函数,再基类析构函数析构函数°复习:析构函数的功能在对象消亡之前进行必要的清理工作87class TColor{class TColor{private:private: string _color; string _color;public:public: TColor(string color="BLACK") { TColor(string color="BLACK") { cout<<"TColor cout<<"TColor构造函数构造函数"< v当派生当派生类对象消亡象消亡时,系,系统调用析构函数用析构函数的的顺序与建立派生序与建立派生类对象象时调用构造函数用构造函数的的顺序序正正好相反好相反,即先,即先调用用派生派生类的析构函数的析构函数,再,再调用用其其对象数据成象数据成员的析构函数的析构函数,最后,最后调用基用基类的的析构函数析构函数 8.3.4 8.3.4 派生派生类的析构函数的析构函数 97第第8 8章章 继承与派生承与派生8.1 8.1 继承的概念承的概念8.2 8.2 定定义基基类和派生和派生类8.3 8.3 构造函数和析构函数构造函数和析构函数8.4 8.4 转换与与继承承988.4 8.4 转换与与继承承v深入了解派生深入了解派生类的成的成员的布局方式的布局方式v派生派生类对象与基象与基类对象之象之间转换的一般的一般规则998.4.1 8.4.1 派生派生类到基到基类的的转换v派生派生类到基到基类的的转换有以下三种情况:有以下三种情况:§派生派生类对象象转换为基基类对象;象;§基基类对象指象指针指向指向派生派生类对象;象;§用派生用派生类对象象初始化初始化基基类对象的引用象的引用100public:public: TCircle(int mx=0, int my=0, int mr=1): TCircle(int mx=0, int my=0, int mr=1): TShape(mx, my) { r = mr; }TShape(mx, my) { r = mr; } void Show() {TShape::Show();cout<<"\tr="< v类的的继承性是承性是软件重用的一种重要机制件重用的一种重要机制v类的的继承承是在是在现有有类的基的基础之上,之上,创建新建新类的机的机制制称称现有的有的类为基基类,,新建立的新建立的类为派生派生类v派生派生类可以以可以以公有、保公有、保护和私有和私有继承承三种方式三种方式继承基承基类;;派生派生类继承了基承了基类中除中除构造函数构造函数和和析构析构函数函数之外的所有成之外的所有成员v派生派生类的成的成员函数函数可以可以访问基基类的公有成的公有成员和保和保护成成员;;105总结v派生派生类的成的成员函数不能直接函数不能直接访问基基类中的中的私有成私有成员v派生派生类继承了基承了基类中有用的成中有用的成员,,发展了其自身的展了其自身的处理能力v派生派生类定定义自己的构造函数和析构函数自己的构造函数和析构函数,在定,在定义派派生生类的构造函数的构造函数时,不,不仅要考要考虑派生派生类新增数据成新增数据成员的初始化,的初始化,还要注意在成要注意在成员初始化列表中初始化列表中对基基类构造函数的构造函数的调用和内嵌用和内嵌对象数据成象数据成员的初始化的初始化 106。












