派生类的声明,继承方式,派生类的构造函数与析构函数,基类与派生类的转换。
author: ZJ
07-12-31
在使用继承时,由于基类是单独编译的,在程序编译时只需对派生类新增的功能进行编译,这就大大提高了调试程序的效率。如果在必要时修改了基类,只要基类的公用接口不变,派生类不必修改,但基类需要重新编译,派生类也必须重新编译,否则不起作用。
1.派生类的声明
声明派生类的一般形式为
class 派生类名:[继承方式] 基类名{
派生类新增成员;
};
|
继承方式包括:public/private/protected,继承方式是可选的,如果不写,则默认为private。具体形式可如下,
class Time{//基类
private:
int hour;
int min;
int sec;
};
class LocalTime:public Time{//派生类
public:
void show();
private:
string zone;
};
|
注意,
【1】派生类把基类全部成员继承下来,但不包括构造函数与析构函数,所以一般应当自己定义派生类的构造函数与析构函数。
【2】可以改变基类成员在派生类中的访问属性,这是通过指定继承方式来实现的。
【3】可以在派生类中声明一个与基类同名的成员,则派生类中的新成员会覆盖基类的同名成员(不仅应使函数名相同,函数的参数表(参数个数和参数类型)也应相同)。
2.继承方式
继承方式包括:public/private/protected。public继承,基类的公有成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有;private继承,基类的公有成员和保护成员在派生类中成为私有成员,其私有成员仍为基类私有;protected继承,基类的公有成员和保护成员在派生类中成为保护成员,其私有成员仍为基类私有。总结如下表,
基类成员在派生类中的访问属性
基类中的成员
|
在public派生类中的访问属性
|
在private派生类中的访问属性
|
在protected派生类中的访问属性
|
private成员
|
不可访问
|
不可访问
|
不可访问
|
public成员
|
公有
|
私有
|
保护
|
protected成员
|
保护
|
私有
|
保护
|
3.派生类的构造函数与析构函数
在设计派生类的构造函数时,不仅要考虑派生类所增加的数据成员的初始化,还应当考虑基类的数据成员初始化。解决这个问题的思路是,在执行派生类的构造函数时,调用基类的构造函数。
3.1简单的派生类构造函数
这里定义简单的派生类构造函数为只有一个基类,而且只有一级派生(直接派生),在派生类的数据成员中不包含基类的对象(子对象)。
则简单的派生类构造函数的一般形式为,
派生类构造函数名(总参数列表):基类构造函数函数名(参数列表){
派生类中新增数据成员初始化;
}
|
class Time{//基类
public:
Time(int=0,int=0,int=0); //基类构造函数
protected:
int hour;
int min;
int sec;
};
class LocalTime:public Time{//派生类
public:
LocalTime(string="",int=0,int=0,int=0); //派生类构造函数
void show();
private:
string zone;
};
Time::Time(int h,int m,int s):hour(h),min(m),sec(s){} //基类构造函数
LocalTime::LocalTime(string z,int h,int m,int s):zone(z),Time(h,m,s){}//派生类构造函数
void LocalTime::show(){
cout<<hour<<":"<<min<<":"<<sec<<"@"<<zone<<endl;
}
int main(){
LocalTime ltime("+8",1,1,1);
ltime.show();
system("PAUSE");
return EXIT_SUCCESS;
}
|
3.2有子对象的派生类构造函数
可以在声明一个类时包含类对象成员,即类对象中的内嵌对象,称为子对象(subobject)。
含有子对象的派生类构造函数的一般形式为,
派生类构造函数名(总参数列表)
:基类构造函数函数名(参数列表),子对象名(参数列表){
派生类中新增数据成员初始化;
}
|
class Time{//基类
public:
Time(int=0,int=0,int=0); //基类构造函数
void show();
protected:
int hour;
int min;
int sec;
};
class LocalTime:public Time{//派生类
public:
LocalTime(string,int,int,int,int,int,int); //派生类构造函数
void show();//覆盖基类同名函数
void show_all();
private:
Time o_time; //子对象,基类型
string zone;
};
Time::Time(int h,int m,int s):hour(h),min(m),sec(s){} //基类构造函数
void Time::show(){
cout<<hour<<":"<<min<<":"<<sec<<endl;
}
LocalTime::LocalTime(string z,int h,int m,int s,int h0,int m0,int s0):
zone(z),Time(h,m,s),o_time(h0,m0,s0){} //派生类构造函数
void LocalTime::show(){
cout<<hour<<":"<<min<<":"<<sec<<"@"<<zone<<endl;
}
void LocalTime::show_all(){
cout<<hour<<":"<<min<<":"<<sec<<"@"<<zone<<endl;
o_time.show();
}
int main(){
LocalTime ltime("+8",1,1,1,0,0,0);
ltime.show_all();
system("PAUSE");
return EXIT_SUCCESS;
}
|
此例的子对象是本派生类的基类,也可以是任何一个已定以的类。
3.3多层派生类构造函数
在多层派生的情况下,当前类只需初始化其直接基类的参数(包括子对象)。
class Time{//基类
public:
Time(int=0,int=0,int=0); //基类构造函数
void show();
protected:
int hour;
int min;
int sec;
};
class LocalTime:public Time{//1层派生类
public:
LocalTime(string,int,int,int); //1层派生类构造函数
LocalTime(string,int,int,int,int,int,int); //1层派生类构造函数
void show();
void show_all();
private:
Time o_time; //子对象
string zone;
};
class EndTime:public LocalTime{//2层派生类
public:
EndTime(string,int,int,int,string); //2层派生类构造函数
void show();
private:
string end;
};
Time::Time(int h,int m,int s):hour(h),min(m),sec(s){} //基类构造函数
void Time::show(){
cout<<hour<<":"<<min<<":"<<sec<<endl;
}
LocalTime::LocalTime(string z,int h,int m,int s):
zone(z),Time(h,m,s){} //1层派生类构造函数
LocalTime::LocalTime(string z,int h,int m,int s,int h0,int m0,int s0):
zone(z),Time(h,m,s),o_time(h0,m0,s0){} //1层派生类构造函数
void LocalTime::show(){
cout<<hour<<":"<<min<<":"<<sec<<"@"<<zone<<endl;
}
void LocalTime::show_all(){
o_time.show();
cout<<hour<<":"<<min<<":"<<sec<<"@"<<zone<<endl;
}
EndTime::EndTime(string z,int h,int m,int s,string e):
end(e),LocalTime(z,h,m,s){} //2层派生类构造函数
void EndTime::show(){
LocalTime::show();
cout<<"end@"<<end<<endl;
}
int main(){
EndTime etime("+8",1,1,1,"12:23:33");
etime.show();
system("PAUSE");
return EXIT_SUCCESS;
}
|
3.4关于派生类中的构造函数与析构函数调用顺序
【1】调用派生类构造函数的顺序是,先调用基类构造函数,对基类数据成员初始化;再调用子对象构造函数,对子对象数据成员初始化;最后调用派生类构造函数本身,对派生类数据成员初始化。
【2】调用派生类析构函数的顺序与构造函数的顺序正好相反,先执行派生类自己的析构函数,对派生类新增的成员进行清理,然后调用子对象的析构函数,对子对象进行清理,最后调用基类的析构函数,对基类进行清理。
4.基类与派生类的转换
公共派生类具有基类的全部功能,所有基类能够实现的功能,公用派生类都能实现。而非公用派生类(private/protected)不能实现基类的全部功能。因此,只有公用派生类才是基类真正的子类型,它完整地继承了基类的功能。
4.1派生类对象可以向基类对象赋值
可以用子类(即公用派生类)对象对其基类对象赋值。
A a;//定义基类A对象a
B b;//定义A的公用派生类B的对象b
a=b;//用派生类B对象b对基类对象a赋值
|
在赋值时会舍弃派生类自己的成员,所谓赋值只是对数据成员赋值,对成员函数不存在赋值问题。
4.2派生类对象可以替代基类对象向基类对象的引用进行赋值或初始化
A a; //定义基类A对象a
B b; //定义A的公用派生类B的对象b
A &r=b;//定义基类A对象的引用r,并用派生类B对象b对其初始化
或
A &r=a;//定义基类A对象的引用r,并用a对其初始化
r=b;//用派生类B对象b对a的引用r赋值
|
当对引用r重新复制b时,r并不是b的别名,也不与b共享同一段存储单元。它只是b中基类部分的别名,r与b中基类部分共享同一段存储单元,r与b具有相同的起始地址。
4.3函数参数是基类对象或其引用,相应的实参可以用子类对象
此时该函数只能调用派生类中基类的成员。
4.4指向基类对象的指针变量可以指向派生类对象
此时该指针只能调用派生类中基类的成员。
本文出自 “子 孑” 博客,请务必保留此出处http://zhangjunhd.blog.51cto.com/113473/57539