C++程序用不同的类定义来表示一组数据以及对这些数据的操作与处理,而类之间往往具有某种关系,“继承与派生”就是类间的一种常用关系。
例如,交通工具→ 汽车 → 轿车 → 红旗轿车。
具有层次关系!
汽车 是一种特殊的 交通工具
轿车 是一种特殊的 汽车
红旗轿车 是一种特殊的 轿车
只要定义清楚了“交通工具”,那么在定义“汽车”时(注意,它就是交通工具),只需再说明它的特殊性(而不必重新从头定义!)。
同理,只要定义清楚了“轿车”,那么在定义“红旗轿车”时(注意,它就是轿车),只需再说明它的特殊性(根本不必重新从头定义!)。
又例如,公司四种雇员档案的管理:
employee(雇员): 姓名、年龄、工资;
manager(经理): 姓名、年龄、工资、行政级别;
engineer(工程师): 姓名、年龄、工资、专业、学位;
director(高级主管): 姓名、年龄、工资、专业、学位、职务。
C++提供了类定义的派生和继承功能,能很好地解决上述问题(使代码可重用,避免重复!)。
若类A是类B的基类(父类),则类B是类A的派生类(子类)。
也可以说,类B(子类)继承了类A(父类);或说,类A(父类)派生出类B(子类)。
假设公司雇员分为:雇员(employee)、经理(manager)、工程师(engineer)、高级主管(director)。而且假定只关心这几类雇员各自的如下一些数据:
employee(雇员)类: 姓名、年龄、工资;
manager(经理)类: 姓名、年龄、工资、行政级别;
engineer(工程师)类: 姓名、年龄、工资、专业、学位;
director( 高级主管)类:姓名、年龄、工资、专业、学位、职务
#include <iostream.h>
#include <string.h>
class employee {
//employee类(类型),将作为其它几个类的基类
shortage;
float salary;
protected:
char * name;//功能和private差不多,但是不能被派生类访问
public:
employee (short ag, float sa, char * na){
age=ag;
salary=sa;
name=new char[strlen(na)+1];
strcpy(name,na);
}
voidprint () const{
cout<<" "<<name<<": ";
cout<<age<<" : ";
cout<<salary<<endl;
}
~employee() {delete[]name;}//析构函数
};
class manager:public employee { //派生类
int level;
public:
manager(shortag,float sa,char* na,intlev)
:employee (ag,sa,na) { //对基类初始化负责
level=lev;
}
void print()const {
employee::print(); //调用基类print显示“共性”数据
cout <<" level:"<<level<<endl;
}
};
class engineer:public employee {
char speciality,adegree;
public:
...
};
enumptitle{PS,GM,VPS,VGM};//枚举类型
class director:public manager {
ptitle post;
public:
...
};
void main() { //主函数
employee emp1(23,610.5,"zhang"),emp2(27,824.75,"zhao");
managerman1(32,812.45,"li",11), man2(34,1200.5,"cui",7);
engineereng(26,1420.10,"meng",'E','M');
directordir(38,1800.2,"zhou",2,GM);
emp1.print();
emp2.print();
man1.print();
man2.employee::print(); //调用基类的print
eng.print();
dir.print();
}
程序执行后的显示结果如下:
zhang:23 : 610.5
zhao:27 : 824.75
li: 32 : 812.45
level:11
cui: 34 : 1200.5
meng:26 : 1420.1
speciality:E
academic degree:M
zhou:38 : 1800.2
level:2
post:1
派生类的定义及其构造和析构函数
. 派生类的定义
class <派生类类型名> :<基类表> {
private:
<各私有成员说明>;
public:
<各公有成员说明>;
protected:
<各保护成员说明>;
<以关键字friend开头的友元说明>;
};
<基类表>的一般格式为:
<派生方式><基类名1>,... ,<派生方式> <基类名n>
而<派生方式>又可为private、public或protected。
派生方式(基类 在基类中的 在派生类中
的被继承方式) 存取权限 的存取权限
==================================================
public public public
public potected protected
public private (inaccessible)
potected public potected
potected potected protected
potected private (inaccessible)
private public private
private potected private
private private (inaccessible)
==================================================
public派生方式:使基类的公有成员和保护成员在派生类中仍然是公有成员和保护成员,而基类的私有成员不可在派生类中被存取。
protected派生方式:使基类的公有成员和保护成员在派生类中都变为保护成员,而基类的私有成员不可在派生类中被存取。
private派生方式:使基类的公有成员和保护成员在派生类中都变为私有成员,而基类的私有成员不可在派生类中被存取。
1) 不可访问的成员 -- 基类的private私有成员被继承过来后,这些成员在派生类中是不可访问的。
2) 私有成员-- 包括在派生类中新增加的private私有成员以及从基类私有继承过来的某些成员。这些成员在派生类中是可以访问的。
3) 保护成员 -- 基类对象是不可以访问的包括在派生类中新增加的potected保护成员以及从基类继承过来的某些成员。这些成员在派生类中是可以访问的。
4) 公有成员 -- 包括在派生类中新增加的public公有成员以及从基类公有继承过来的基类的public成员。这些成员不仅在派生类中可以访问,而且在建立派生类对象的模块中,也可以通过对象来访问它们。
2. 派生类的构造函数和析构函数
派生类的构造函数的一般格式如下:
<派生类名>(<参数总表>):<初始化符表>
{
<构造函数体>
}
而 <初始化符表> 按如下格式构成:
<基类名1>(<基类参数表1>), ... ,<基类名n>(<基类参数表n>),<对象成员名1>(<对象成员参数表1>), ... ,<对象成员名m>(<对象成员参数表m>)
(注:若无对象成员时,则不出现此后半部分;基类名与对象成员名的次序无关紧要,各自出现的顺序可以任意)
派生类构造函数执行的一般次序如下:
(1) 调用各基类的构造函数,调用顺序继承时的声明顺序。
(2) 若派生类含有对象成员的话,调用各对象成员的构造函数,调用顺序按照声明顺序。
(3) 执行派生类构造函数的函数体。
析构派生类对象时,其执行次序恰与构造时的次序相反。
#include<iostream.h>
class CB{
intb;
public:
CB(intn){ b=n; cout<<"CB::b="<<b<<endl;};
~CB(){cout<<"CBobjis destrcting"<<endl;};
};
class CC{
intc;
public:
CC(intn1,int n2){ c=n1; cout<<"CC::c="<<c<<endl;};
~CC(){cout<<"CCobjis destructing"<<endl;};
};
class CD:publicCB,public CC{
int d;
public:
CD(int n1,int n2,int n3,int n4)
:CC(n3,n4),CB(n2){
d=n1; cout<<"CD::d="<<d<<endl;
};
~CD(){cout<<"CDobj is destructing"<<endl;};
};
void main(void){
CD CDobj(2,4,6,8);
}
运行结果为:
CB::b=4
CC::c=6
CD::d=2
CDobjis destructing
CCobjis destructing
CBobjis destrcting
思考: 将派生类 CD 改写为如下形式后,请给出输出结果
classCD:publicCB,publicCC {
intd;
CC obcc;
CB obcb;
public:
CD(intn1,int n2,int n3,int n4) :CC(n3,n4), CB(n2), obcb(100+n2),obcc(100+n3,100+n4){
d=n1; cout<<"CD::d="<<d<<endl;
};
~CD(){cout<<"CDobjis destructing"<<endl;};
};
输出:
CB::b=4
CC::c=6
CC::c=106
CB::b=104
CD::d=2
CDobjis destructing
CBobjis destrcting.
CCobjis destructing
CCobjis destructing
CBobjis destrcting
3.其他特征的继承关系1.友元关系
基类的友元不继承。即,如果基类有友元类或友元函数,则其派生类不因继承关系也有此友元类或友元函数。
另一方面,如果基类是某类的友元,则这种友元关系是被继承的。即,被派生类继承过来的成员,如果原来是某类的友元,那么它作为派生类的成员仍然是某类的友元。总之:
2.静态成员的继承
如果基类中被派生类继承的成员是静态成员,则其静态属性也随静态成员被继承过来。
具体地说,如果基类的静态成员是公有的或是保护的,则它们被其派生类继承为派生类的静态成员。即:
(1)这些成员通常用“<类名>::<成员名>”方式引用或调用。
(2)这些成员无论有多少个对象被创建,都只有一个拷贝。它为基类和派生类的所有对象所共享。