C++大学基础教程第 9章 继承与派生
2009-7-29 -2-
第 9章 继承与派生
9.1 继承的概念
9.2 继承方式
9.3 派生类构造函数的定义
9.4 多继承
2009-7-29 -3-
第 9章 继承与派生软件重用
2009-7-29 -4-
第 9章 继承与派生类具有封装性、继承性和多态性
2009-7-29 -5-
继承的概念自行车
2009-7-29 -6-
继承的概念
2009-7-29 -7-
继承的概念
2009-7-29 -8-
继承的概念
2009-7-29 -9-
Bicycle
M ountain
Bikes
Ra cin g
Bikes
Tande m
Bikes
is- a relations hips
继承的概念
2009-7-29 -10-
第 9章 继承与派生主要介绍:
继承和派生的概念
继承方式;
派生类的构造函数与析构函数;
多继承中的二义性
虚基类 。
2009-7-29 -11-
9.1 继承的概念类的继承 是在现有类的基础之上,创建新类的机制 。 称现有的类为 基类,新建立的类为 派生类 。
新类继承了基类的属性和行为
新类是基类的特殊情况。
不必从,草稿,开始创建特殊的程序对象继承是处理,特殊情况,的面向对象编程机制
2009-7-29 -12-
派生类的定义格式
class 派生类名:继承方式 基类名
{
public:
//派生类公有成员 …
private:
//派生类私有成员 …
}
派生类只有一个直接基类为 单继承
2009-7-29 -13-
例,定义基类 shape
class shape
{
private:
int m_x,m_y; //位置
char m_color; //颜色
public:
void setposition(int x,int y);
void setcolor(char color);
int getx();
int gety();
char getcolor();
};
2009-7-29 -14-
定义派生类 (等边三角形类 )
class 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;
};
2009-7-29 -15-
派生新类,
circle 圆形
rectangle 矩形
triangle 三角形基类称为 父类派生类称为 子类
shape
circle rectangle triangle
2009-7-29 -16-
派生类的定义格式
class 派生类名:继承方式 基类名 1,… 继承方式 基类名 n
{
public:
//派生类公有成员 …
private:
//派生类私有成员 …
}
有多个基类派生类有多个基类为多继承
2009-7-29 -17-
例,已有基类 base1,base2,base3,定义派生类 deriver
class deriver:public base1,public base2,private base3
{
private:
int m_derdata;
public:
void derfunction();
};
2009-7-29 -18-
注意每一个“继承方式”,只用于限制对紧随其后之基类的继承。
类的继承方式是派生类对基类成员的继承方式 。
类的继承方式指定了类外对象对于派生类从基类继承来的成员的访问权限 。
2009-7-29 -19-
直接基类和间接基类
class base
{……
};
class deriver1:public base
{ ……
};
class deriver2:public deriver1
{……
}
父类被称为子类的 直接基类
父类的父类或更高层次的父类被称为这个子类的 间接基类
2009-7-29 -20-
派生与继承的实例公司人员管理系统,
小型公司人员分为,经理、兼职技术人员、销售经理和兼职推销员,
要求,
存储所有人员的姓名、编号、级别、当月薪水,计算月薪总额并显示全部信息。
人员编号在生成人员信息时同时生成,每输入一个人员信息编号顺序加 1。
程序能够对不同人员按不同方法提升级别,月薪的计算方法是:
经理拿固定月薪 ;
兼职技术人员按工作小时数领取月薪 ;
兼职推销员的报酬按该推销员当月销售额提成 ;
销售经理既拿固定月薪也领取销售提成。
2009-7-29 -21-
派生与继承的实例分析:
·描述全体职员的共性 ( 基类 )
·描述每一类特殊人员 ( 派生类 )
2009-7-29 -22-
class employee
{
protected:
char *name; //姓名
int individualEmpNo; //个人编号
int grade; //级别
float accumPay; //月薪总额
static int employeeNo; //本公司职员编号目前最大值
public:
employee(); //构造函数
~employee(); //析构函数
void pay(); //计算月薪函数
void promote(int);//升级函数
void displayStatus(); //显示人员信息
};
2009-7-29 -23-
class technician,public employee //兼职技术人员类
{
private:
float hourlyRate; //每小时酬金
int workHours; //当月工作时数
public:
technician(); //构造函数
void pay(); //计算月薪函数
void displayStatus(); //显示人员信息
};
新增加的成员同名覆盖,改造基类成员派生类的成员,
1,从基类继承的成员 ;
2,改造基类成员 ;
3,添加派生类新成员,
2009-7-29 -24-
9.2 继承方式三种继承方式
public,protected,private
不同继承方式的影响主要体现在:
派生类 成员 对基类成员的访问控制。
派生类 对象 对基类成员的访问控制。
定义派生类时要声明继承方式
2009-7-29 -25-
9.2.1,派生类的定义派生类的定义形式:
class 派生类名:继承方式 基类 1,
继承方式 基类 2,…,继承方式 基类 n
{
派生类成员声明;
};
2009-7-29 -26-
例如,
设已有基类 base1和 base2,定义派生类
deriver.
class deriver,public base1,private base2
{ private:
int newmember;
public:
void newfun();
};
2009-7-29 -27-
单继承情况,派生类的定义
class 派生类名:继承方式 基类名
{
派生类成员声明
};
2009-7-29 -28-
例 9.1 图形类及其派生类的声明
class 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;
};
2009-7-29 -29-
class Circle,public Shape
{
public:
Circle(int x,int y,float r=1,char color='R');
float GetRadius () const;
void SetCircle(int x,int y,float r,char color);
void Draw();
private:
float m_Radius;
};
2009-7-29 -30-
class 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;
};
2009-7-29 -31-
class Rectangle,public Shape
{
public:
Rectangle(int x,int y,char color,int length=10,
int width=10);
int GetWidth() const;
int GetHeight() const;
void Draw();
void SetRectangle (int x,int y,char color,int
length,int width);
private:
int m_Width;
int m_Length;
};
2009-7-29 -32-
从基类继承的成员
派生类的成员包括:( 1)继承基类的成员,( 2)派生类定义时声明的成员。
派生类自己增加的成员,完成两个需求,(1)修改基类成员,( 2)描述新的特征或方法。
m_color;
m_x; m_y;
GetX();SetX();
GetY();SetY();
GetColor();
SetColor();
m_Radius;
GetRadius ()
SetCircle();
Draw();
m_color;
m_x; m_y;
GetX();SetX();
GetY();SetY();
GetColor();
SetColor();
m_SideLength;
GetSideLength();
SetTriangle();
Draw();
m_color;
m_x; m_y;
GetX();SetX();
GetY();SetY();
GetColor();
SetColor();
m_Width; m_Length;
GetWidth();
GetHeight();
Draw();
SetRectangle();
派生类增加的成员
2009-7-29 -33-
同名覆盖派生类修改基类的成员,是在派生类中声明了一个与基类成员同名的新成员。在派生类作用域内或者在类外通过派生类的对象直接使用这个成员名,只能访问到派生类中声明的同名新成员,这个新成员覆盖了从基类继承的同名成员,这种情况称为 同名覆盖 。
2009-7-29 -34-
class Shape
{
public:

void Draw(){};
protected:

};
class 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;
};
2009-7-29 -35-
例 9.2 同名覆盖示例
#include<iostream>
using namespace std;
class base
{
public:
void function(){cout<<"function of class base"<<endl;}
};
class deriver,public base
{
public:
void function(){cout<<"function of class
deriver"<<endl;}
};
2009-7-29 -36-
void main()
{
deriver derobj;
derobj.function();
}
输出结果,
function of class deriver
2009-7-29 -37-
例 9.3 派生类成员函数对基类同名函数的改进。
//number.h
class Number
{
protected:
int m_number;
public:
int GetNumber(){ return m_number; }
void SetNumber(int n){ m_number=n;}
void Prime();
};
2009-7-29 -38-
//number.cpp
#include<iostream>
#include "number.h"
using namespace std;
void Number::Prime()
{ int i;
for(i=2; i<m_number; i++) //找 m_number的因数
{ if(m_number %i==0) break; }
if(m_number ==i) //判断 m_number是否被小于 m_number的数整除
cout <<m_number <<" is prime"<<endl;
else
cout <<m_number <<" isn't prime"<<endl;
}
2009-7-29 -39-
//DerNumber.h
class DerNumber,public Number
{
public:
void Prime();
};
2009-7-29 -40-
//DerNumber.cpp
#include<iostream>
#include<cmath>
#include "number.h"
#include "DerNumber.h"
using namespace std;
void DerNumber::Prime()
{ double sqrtm=sqrt(m_number); //用到 math.h
int i;
for(i=2; i<=sqrtm; i++)
{ if(m_number %i==0) break; }
if(sqrtm<i) cout <<m_number <<" is prime.\n";
else cout <<m_number <<" isn't prime.\n";
}
2009-7-29 -41-
//使用模块
#include<iostream>
#include<ctime>
#include "number.h"
#include "DerNumber.h"
using namespace std;
void main()
{
Number aNum;
DerNumber aDerNum;
clock_t start,finish;
2009-7-29 -42-
double elapsed_time1,elapsed_time2;
int i;
unsigned int max(100000);
time( &start );
for(i=10000;i<=max;i++)
{
aNum.SetNumber(i);
cout<<aNum.GetNumber()<<" "<<endl;
aNum.Prime();
}
time( &finish );
2009-7-29 -43-
elapsed_time1 = difftime( finish,start );
time( &start );
for(i=10000;i<=max;i++)
{
aDerNum.SetNumber(i);
cout<<aDerNum.GetNumber()<<" "<<endl;
aDerNum.Prime();
}
time( &finish );
elapsed_time2 = difftime( finish,start );
2009-7-29 -44-
cout<<"Delay for using Number class,"<<elapsed_time1
<<" seconds"<<endl;
cout<<"Delay for using DerNumber class,"
<<elapsed_time2<<" seconds"<<endl;
}
输出结果 (部分 ):
Delay for using Number class,157 seconds
Delay for using DerNumber class,151 seconds
2009-7-29 -45-
9.2.2,继承的访问控制派生类继承了基类 中除构造函数和析构函数之外的所有成员 。
2009-7-29 -46-
9.2.2,继承的访问控制三种继承方式,
公有继承 (public)
私有继承 (private)
保护继承 (protected)
2009-7-29 -47-
9.2.2,继承的访问控制不同的继承方式使得派生类从基类继承的成员具有不同的访问控制权限,以实现数据的安全性和共享性控制 。
不同继承方式决定的不同访问控制权限体现在:
派生类的成员函数 对其继承的基类成员的访问控制;
其它模块通过派生类对象 对其继承的基类成员的访问控制 。
2009-7-29 -48-
1,公有继承公有继承的派生类定义形式:
class 派生类名,public 基类名
{
派生类新成员定义;
}
2009-7-29 -49-
公有继承
public是定义公有继承方式的关键字公有继承方式定义的派生类,继承了基类中 除构造函数和析构函数外 的其余成员:公有成员、保护成员和私有成员被继承的基类成员在派生类中仍将保持其原来的访问属性。
派生类的成员函数 可以访问基类的公有成员和保护成员,不能访问基类的私有成员 ;
派生类以外的其它函数 可以通过派生类的对象,访问从基类继承的公有成员,但不能访问从基类继承的保护成员和私有成员。
2009-7-29 -50-
class 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;
};
2009-7-29 -51-
class 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;
};
派生类中的 成员函数 可以直接访问基类中的 public和
protected成员,但不能访问基类的 private
成员。
2009-7-29 -52-
main()
{
Rectangle rect;
cout<<rect.X; //?
cout<<rect.GetX();//
}
使用派生类的 对象只能访问基类的
public成员
2009-7-29 -53-
class 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;
};
派生类中的 成员函数 可以直接访问基类中的 public和
protected成员,但不能访问基类的 private
成员。
2009-7-29 -54-
class 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;
};
2009-7-29 -55-
class 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;
};
派生类中的 成员函数 可以直接访问基类中的 public和
protected成员,但不能访问基类的 private
成员。
2009-7-29 -56-
main()
{
Rectangle rect;
cout<<rect.X; //?
cout<<rect.GetX();//
}
使用派生类的 对象只能访问基类的
public成员依然错误
!
2009-7-29 -57-
2.私有继承私有继承的派生类定义形式:
class 派生类名,private 基类名
{
派生类新成员定义;
}
2009-7-29 -58-
私有继承
private是定义私有继承方式的关键字以私有继承方式定义的派生类,继承了基类中可以继承的成员:公有成员、保护成员和私有成员,这些成员在派生类中的访问属性都是私有的。
派生类的成员函数 可以访问基类的公有成员和保护成员,不能访问基类的私有成员。
派生类以外的其它函数 则不能通过派生类的对象访问从基类继承的任何成员。
2009-7-29 -59-
class 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;
};
2009-7-29 -60-
class 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;
};
派生类中的 成员函数可以直接访问基类中的 public和 protected
成员,但不能访问基类的 private成员。
2009-7-29 -61-
class 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;
};
派生类中的 成员函数可以直接访问基类中的
public和 protected成员,但不能访问基类的
private成员。
2009-7-29 -62-
class 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;
};
2009-7-29 -63-
class 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;
};
2009-7-29 -64-
main()
{
Rectangle rect;
cout<<rect.X; //?
cout<<rect.GetX();//?
}
使用派生类的 对象不能访问基类中的任何成员。
错误 !
2009-7-29 -65-
3,保护继承保护继承的派生类定义形式:
class 派生类名,protected 基类名
{
派生类新成员定义;
}
2009-7-29 -66-
保护继承
protected是定义保护继承方式的关键字以保护继承方式定义的派生类,继承了基类中可以继承的成员:公有成员、保护成员和私有成员。
其中基类的公有成员和保护成员在派生类中访问控制属性变成保护类型的,基类的私有成员保持原来属性。
派生类的成员函数 可以访问基类的公有成员和保护成员,不能访问基类的私有成员。
派生类以外的其它函数 则不能通过派生类的对象访问从基类继承的任何成员。
2009-7-29 -67-
class 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;
};
2009-7-29 -68-
class 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;
};
派生类中的 成员函数可以直接访问基类中的 public和 protected
成员,但不能访问基类的 private成员。
2009-7-29 -69-
class 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;
};
派生类中的 成员函数可以直接访问基类中的
public和 protected成员,但不能访问基类的
private成员。
2009-7-29 -70-
class 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;
};
2009-7-29 -71-
class 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;
};
派生类中的 成员函数可以直接访问基类中的
public和 protected成员,但不能访问基类的
private成员。
2009-7-29 -72-
main()
{
Rectangle rect;
cout<<rect.X; //?
cout<<rect.GetX();//
}
使用派生类的 对象不能访问基类中的任何成员。
错误 !
2009-7-29 -73-
p r i v a t e p r i v a t e p r i v a t e p r i v a t e
p r i v a t e p r o t ec t ed p r o t ec t ed p r o t ec t ed
p r i v a t e p r o t ec t ed p u b l i c p u b l i c
p riv a t e p r o t ec t ed p u b l i c
存取方式继承类型
2009-7-29 -74-
9.3 派生类构造函数的定义派生类继承了基类中除构造函数和析构函数之外的所有成员 。
基类的构造函数和析构函数不能被派生类所继承,
派生类需要自己定义的构造函数和析构函数 。
2009-7-29 -75-
9.3.2 派生类的构造函数派生类构造函数的一般形式,
派生类名,:派生类名 (基类所需的形参,本类成员所需的形参 ):
基类 1(基类参数表 1),…,基类 n(基类参数表 n),
对象成员 1(对象参数表 1),…,对象成员 m(对象参数表 m)
{
本类基本类型数据成员初始化;
}
2009-7-29 -76-
派生类的构造函数单继承时的构造函数派生类名,:派生类名 (基类所需的形参,本类成员所需的形参 ):
基类名 (参数 )
{
本类成员初始化赋值语句;
}
2009-7-29 -77-
class Point //基类 Point类的定义
{
public,//公有函数成员
Point(int xx=0,int yy=0) {X=xx;Y=yy;}
void InitP(int xx=0,int yy=0) {X=xx;Y=yy;}
void Move(int xOff,int yOff) {X+=xOff;Y+=yOff;}
int GetX() {return X;}
int GetY() {return Y;}
private,//私有数据成员
int X,Y;
};
2009-7-29 -78-
class Rectangle,public Point
{
public:
Rectangle(int x,int y,int w,int h);
void InitR(int x,int y,int w,int h)
{InitP(x,y);W=w;H=h;} //派生类访问基类公有成员
void Move(int xOff,int yOff) {Point::Move(xOff,yOff);}
int GetX() {return Point::GetX();}
int GetY() {return Point::GetY();}
int GetH() {return H;}
int GetW() {return W;}
private://新增私有数据
int W,H;
};
2009-7-29 -79-
Rectangle:,Rectangle(int x,int y,int w,int h),Point(x,y)
{
W=w;
H=h;
}; 本类成员初始化赋值语句;
基类所需的形参本类成员所需的形参基类构造函数
2009-7-29 -80-
例 9.5
定义一个派生类 deriver,它是基类
base1和 base2的多继承。 Deriver类还有两个私有的内嵌对象成员。定义派生类
deriver的构造函数。
2009-7-29 -81-
class base1
{
private:
int m_base_data;
public:
base1(int data){m_base_data=data;}
//…
};
2009-7-29 -82-
class base2
{
private:
int m_base_data;
public:
base2(int data){m_base_data=data;}
//…
};
2009-7-29 -83-
class Abc
{
private:
float m_abc_data;
public:
Abc(float data){ m_abc_data=data; }
//…
};
2009-7-29 -84-
class deriver:public base1,public base2
{
private:
Abc m_member1,m_member2;
double m_deriver_data;
public:
deriver(int bd1,int bd2,float id1,float id2,double dd);
};
2009-7-29 -85-
deriver:,deriver(int bd1,int bd2,float id1,float id2,
double dd),base1(bd1),base2(bd2),
m_member1(id1),m_member2(id2)
{
m_deriver_data=dd;
}
2009-7-29 -86-
使用基类无参构造函数
deriver:,deriver(float id1,float id2,
double dd),m_member1(id1),m_member2(id2)
{
m_deriver_data=dd;
}
2009-7-29 -87-
使用对象数据成员的无参构造函数
deriver:,deriver(int bd1,int bd2,double dd):
base1(bd1),base2(bd2)
{
m_deriver_data=dd;
}
2009-7-29 -88-
派生类的构造函数如果基类和对象数据成员的构造函数都无参数,
派生类构造函数形参表中将只包含用于初始化它自己的基本类型数据成员的参数。
如果这个派生类恰好没有基本类型的数据成员,
则其构造函数的形参表为空,可以不定义构造函数,而使用系统提供的默认构造函数。
2009-7-29 -89-
#include<iostream>
using namespace std;
class base
{
private:
int m_data;
public:
void SetData(int data){m_data=data;}
int GetData(){return m_data;}
};
使用系统提供的默认构造函数
2009-7-29 -90-
class deriver:public base
{
private:
int m_member;
public:
void SetMember(int m){ m_member=m;}
int GetMember(){return m_member;}
};
2009-7-29 -91-
void main()
{
int n(10);
deriver obj;
obj.SetMember(n);
cout<<obj.GetMember()<<endl;
}
2009-7-29 -92-
派生类的构造函数基类的构造函数不被继承,需要在派生类中自行定义 。
定义构造函数时,以合适的初值为参数,初始化本类中新增成员。
利用 成员初始化表 隐含调用 基类 和 新增对象数据成员 的构造函数,初始化它们各自的数据成员。
构造函数的调用次序
系统会使用派生类构造函数的形参表的参数调用基类和内嵌对象成员的构造函数。
2009-7-29 -93-
派生类的构造函数系统在 建立派生类 对象时,首先调用基类的构造函数,再调用派生类的构造函数。
系统在 建立组合类 对象时,先调用内嵌子对象的构造函数,在调用组合类的构造函数。
如果 一个派生类又是组合类,则系统先调用其基类的构造函数,再调用其内嵌子对象的构造函数,
再后系统才调用派生类的构造函数。
2009-7-29 -94-
派生类的构造函数如果是 多继承,系统 调用基类构造函数的顺序 是按照定义派生类时这些基类被继承的顺序进行的,
与这些基类构造函数在派生类构造函数成员初始化列表的先后次序无关。
如果派生类有 多个对象数据成员,则系统 调用这些对象数据成员的构造函数的顺序 是依据派生类定义这些成员的顺序进行的,与派生类成员初始化列表中对象数据成员构造函数排列先后次序无关。
2009-7-29 -95-
deriver:,deriver(int bd1,int bd2,float id1,float id2,double dd):
base2(bd2),base1(bd1),m_member2(id2),m_member1(id1)
{
m_deriver_data=dd;
}
构造函数的调用次序
2009-7-29 -96-
9.3.2 派生类的析构函数派生类不能继承基类的析构函数,需要自己定义析构函数,以便在派生类对象消亡之前进行必要的清理工作。
派生类的析构函数只负责清理它新定义的非对象数据成员,对象数据成员由对象成员所属类的析构函数负责析构。
2009-7-29 -97-
#include<iostream>
using namespace std;
class base
{
private:
int m_base_data;
public:
base(int data){m_base_data=data;}
~base(){cout<<"base object deconstruction"<<endl;}
//…
};
2009-7-29 -98-
class Abc
{
private:
float m_abc_data;
public:
Abc(float data){ m_abc_data=data; }
~Abc(){cout<<"Object member deconstruction"<<endl;}
//…
};
2009-7-29 -99-
class deriver:public base
{
private:
double m_deriver_data;
Abc m_member1;
int *m_ptr;
public:
deriver(int bd,float id,double dd);
~deriver();
void function();
};
2009-7-29 -100-
deriver:,deriver(int bd,float id,double dd):base(bd),
m_member1(id)
{
m_deriver_data=dd;
m_ptr=new int[256];
if(m_ptr==NULL)
cout<<"memory error in deriver obj"<<endl;
}
2009-7-29 -101-
deriver::~deriver()
{
if(m_ptr!=NULL)
delete [] m_ptr;
cout<<"Deriver obj deconstruction."<<endl;
}
2009-7-29 -102-
void deriver::function()
{
cout<<"Maybe you want to do something with m_ptr in this
function,"<<endl;
cout<<"Do as you like."<<endl;
}
2009-7-29 -103-
void main()
{
int n(1);
float x(2.0f);
double d(3.0);
deriver obj(n,x,d);
obj.function();
cout<<"The end of main function"<<endl;
}
2009-7-29 -104-
输出结果,
Maybe you want to do something with m_ptr in this function.
Do as you like.
The end of main function
Deriver obj deconstruction.
Object member deconstruction
base object deconstruction
2009-7-29 -105-
派生类的析构函数如果没有特殊指针数据成员需要清理,可以使用由系统提供的默认析构函数。
当派生类对象消亡时,系统调用析构函数的顺序与建立派生类对象时调用构造函数的顺序正好相反,即先调用派生类的析构函数,再调用其对象数据成员的析构函数,最后调用基类的析构函数。
2009-7-29 -106-
9.4 多继承
9.4.1 多继承与二义性多继承类结构中,派生类可能有多个直接基类或间接基类,充分体现了软件重用的优点,但也可能会引起成员访问的二义性或不确定性问题。
例 9.7 多继承时的二义性
#include<iostream>
using namespace std;
class base
{private:
int m_data;
public:
base(int m)
{ m_data=m;
cout<<"base construction"<<endl;
}
~base(){cout<<"base deconstruction"<<endl;}
void setdata(int data){m_data=data;}
int getdata(int data){ return m_data;}
};
class Fderiver1,public base
{
private:
int m_value;
public:
Fderiver1(int value,int data):base(data)
{ m_value=value;
cout<<"Fderiver1 construction"<<endl;
}
~Fderiver1(){cout<<"Fderiver1 deconstruction"<<endl;}
void setvalue(int value){ m_value=value;}
int getvalue(){ return m_value; }
void fun(){};
};
class Fderiver2,public base
{
private:
int m_number;
public:
Fderiver2(int number,int data):base(data)
{ m_number=number;
cout<<"Fderiver2 construction"<<endl;
}
~Fderiver2(){cout<<"Fderiver2 deconstruction"<<endl;}
void setnumber(int number){ m_number=number;}
int getnumber(){ return m_number; }
void fun(){};
};
class Sderiver,public Fderiver1,public Fderiver2
{private:
int m_attrib;
public:
Sderiver(intattrib,int number,int value,int data):
Fderiver1(value,data),Fderiver2(number,data)
{ m_attrib=attrib;
cout<<"Sderiver construction"<<endl;
}
~Sderiver(){cout<<"Sderiver deconstruction"<<endl;}
void setattrib(int attrib){m_attrib=attrib;}
int getattrib(){return m_attrib;}
void newfun1(){};
int newfun2(){};
};
2009-7-29 -111-
void main()
{
Sderiver object( 3,4,5,6) ;
object.setdata(7);
}
产生二义性
2009-7-29 -112-
base
Fderiver1 Fderiver2
Sderiver
图9- 3 多继承类结构
m_data
m_value
m_data
m_number
m_attrib

Fderiver1
继承从
Fderiver2
继承
Sdreriver
自己声明的部分图9 - 4 多继承的派生类对象内存使用
2009-7-29 -113-
9.4.2 虚基类为解决二义性问题,将共同基类设置为虚基类,创建派生类对象时,虚基类的构造函数只会调用一次,
虚基类的成员在第三层派生类对象中就只有一份拷贝,不会再引起二义性问题。
2009-7-29 -114-
虚基类语法形式:
class 派生类名,virtual 继承方式 基类名
{
//……
}
在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧随其后的基类起作用 。
2009-7-29 -115-
虚基类在多继承类结构中,说明虚基类之后,虚基类的成员在派生类中将不会因继承关系对虚基类的多次继承而形成多份拷贝,只为最远的派生类提供唯一的基类成员,消除了多继承结构中的二义性问题。
需要注意的是在第一级继承时就要将共同基类设计为虚基类。
class Fderiver1,virtual public base
{
private:
int m_value;
public:
Fderiver1(int data,int value):base(data)
{ m_value=value;
cout<<"Fderiver1 construction"<<endl;
}
~Fderiver1(){cout<<"Fderiver1 deconstruction"<<endl;}
void setvalue(int value){ m_value=value;}
int getvalue(){ return m_value; }
void fun(){};
};
class Fderiver2,virtual public base
{
private:
int m_number;
public:
Fderiver2(int data,int number):base(data)
{
m_number=number;
cout<<"Fderiver2 construction"<<endl;
}
~Fderiver2(){cout<<"Fderiver2 deconstruction"<<endl;}
void setnumber(int number){ m_number=number;}
int getnumber(){ return m_number; }
void fun(){};
};
class Sderiver,public Fderiver1,public Fderiver2
{
private:
int m_attrib;
public:
Sderiver(intdata,int value,int number,int attrib),
base(data),Fderiver1(data,value),Fderiver2(data,number)
{ m_attrib=attrib;
cout<<"Sderiver construction"<<endl; }
~Sderiver(){cout<<"Sderiver deconstruction"<<endl;}
void setattrib(int attrib){m_attrib=attrib;}
int getattrib(){return m_attrib;}
void newfun1(){};
int newfun2(){};
};
2009-7-29 -119-
多继承派生类构造函数的定义在包含虚基类的继承结构中,系统在建立派生类的对象时,调用构造函数的顺序是,
( 1)首先按照虚拟基类被继承的顺序,调用它们的构造函数;
( 2) 其次按照非虚拟基类被继承的顺序,调用它们的构造函数;
( 3) 再次按照对象数据成员声明的顺序,调用它们的构造函数;
( 4) 最后调用派生类自己的构造函数 。
2009-7-29 -120-
多继承派生类构造函数的定义如果基类使用带参的构造函数,则派生类需要在其构造函数的形式参数表中提供相应的参数给基类,对其对象数据成员亦如此 。
如果基类和对象数据成员都使用默认构造函数,派生类也没有需要初始化的基本类型数据成员,也可以使用默认构造函数 。
析构派生类的对象时,析构函数的调用顺序正好与构造函数的调用顺序相反 。
2009-7-29 -121-
#include<iostream>
using namespace std;
void main()
{
int d (1),v (2),n (3),a (4);
Sderiver(d,v,n,a);
//add some function,…
cout<<"the end of main"<<endl;
}
2009-7-29 -122-
输出结果,
base construction
Fderiver1 construction
Fderiver2 construction
Sderiver construction
the end of main
Sderiver deconstruction
Fderiver2 deconstruction
Fderiver1 deconstruction
base deconstruction