C++:单继承与转型

 
派生类的声明,继承方式,派生类的构造函数与析构函数,基类与派生类的转换。
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/protectedpublic继承,基类的公有成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有;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对象ba的引用r赋值
当对引用r重新复制b时,r并不是b的别名,也不与b共享同一段存储单元。它只是b中基类部分的别名,rb中基类部分共享同一段存储单元,rb具有相同的起始地址。
 
4.3函数参数是基类对象或其引用,相应的实参可以用子类对象
此时该函数只能调用派生类中基类的成员。
 
4.4指向基类对象的指针变量可以指向派生类对象
此时该指针只能调用派生类中基类的成员。

本文出自 “子 孑” 博客,请务必保留此出处http://zhangjunhd.blog.51cto.com/113473/57539

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值