派生类与基类的转换

原创 2016年06月02日 12:59:23


派生类与基类的转换


只有公用派生类才是基类真正的子类型,它完整地继承了基类的功能。

基类与派生类对象之间有赋值兼容关系,由于派生类中包含从基类继承的成员,因此可以将派生类的值赋给基类对象,在用到基类对象的时候可以用其子类对象代替。

 

具体表现在以下几个方面:

派生类对象可以向基类对象赋值。

 可以用子类(即公用派生类)对象对其基类对象赋值。如

   Aa1; //定义基类A对象a1

   Bb1; //定义类A的公用派生类B的对象b1

  a1=b1; //用派生类B对象b1对基类对象a1赋值

在赋值时舍弃派生类自己的成员。

 

实际上,所谓赋值只是对数据成员赋值,对成员函数不存在赋值问题。请注意: 赋值后不能企图通过对象a1去访问派生类对象b1的成员,因为b1的成员与a1的成员是不同的。

 

假设age是派生类B中增加的公用数据成员,分析下面的用法:

   a1.age=23;//错误,a1中不包含派生类中增加的成员

  b1.age=21; //正确,b1中包含派生类中增加的成员

应当注意,子类型关系是单向的、不可逆的。BA的子类型,不能说AB的子类型。

 

只能用子类对象对其基类对象赋值,而不能用基类对象对其子类对象赋值,理由是显然的,因为基类对象不包含派生类的成员,无法对派生类的成员赋值。同理,同一基类的不同派生类对象之间也不能赋值。

派生类对象可以替代基类对象向基类对象的引用进行赋值或初始化。

如已定义了基类A对象a1,可以定义a1的引用变量:

   Aa1; //定义基类A对象a1

   Bb1; //定义公用派生类B对象b1

  A& r =a1; //定义基类A对象的引用变量r,并用a1对其初始化

这时,引用变量ra1的别名,ra1共享同一段存储单元。也可以用子类对象初始化引用变量r,将上面最后一行改为

  A& r=b1;//定义基类A对象的引用变量r,并用派生类B对象b1//对其初始化

或者保留上面第3行“A& r=a1;”,而对r重新赋值:

r=b1;//用派生类B对象b1a1的引用变量r赋值

 

注意: 此时r并不是b1的别名,也不与b1共享同一段存储单元。它只是b1中基类部分的别名,rb1中基类部分共享同一段存储单元,rb1具有相同的起始地址。 (r始终是基类的)

如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类对象。如有一函数

fun: void fun(A& r)//形参是类A的对象的引用变量

{

  cout<<r.num<<endl;

} //输出该引用变量的数据成员num

 

函数的形参是类A的对象的引用变量,本来实参应该为A类的对象。由于子类对象与派生类对象赋值兼容,派生类对象能自动转换类型,在调用fun函数时可以用派生类B的对象b1作实参: fun(b1); 输出类B的对象b1的基类数据成员num的值。与前相同,在fun函数中只能输出派生类中基类成员的值。(输出的只能是基类中有的值)

派生类对象的地址可以赋给指向基类对象的指针变量,也就是说,指向基类对象的指针变量也可以指向派生类对象。

11.10 定义一个基类Student(学生),再定义Student类的公用派生类Graduate(研究生) 用指向基类对象的指针输出数据。

本例主要是说明用指向基类对象的指针指向派生类对象,为了减少程序长度,在每个类中只设很少成员。

学生类只设num(学号),name(名字)score(成绩)3个数据成员,

Graduate类只增加一个数据成员pay(工资)

程序如下:

#include <iostream>

#include <string>

Graduate::Graduate(int n, string nam,floats,float p):Student(n,nam,s),pay(p){ }

using namespace std;

class Student//声明Student

{

  public :

  Student(int, string,float );//声明构造函数

  void display( );//声明输出函数

  private :

  int num;

  string name;

  float score;

};

Student::Student(int n, string nam,floats)  //定义构造函数

{

  num=n;

  name=nam;

  score=s;

}

void Student::display( )//定义输出函数

{

  cout<<endl<<num:<<num<<endl;

  cout<<name:<<name<<endl;

  cout<<score:<<score<<endl;

}

class Graduate:public Student//声明公用派生类Graduate

{

  public :

  Graduate(int, string ,float ,float );//声明构造函数

  void display( );//声明输出函数

  private :

  float pay;//工资

};

//定义构造函数

void Graduate::display() //定义输出函数

{

  Student::display(); //调用Student类的display函数

  cout<<pay=<<pay<<endl;

}

int main()

{

  Student stud1(1001,Li,87.5); //定义Student类对象stud1

  Graduate grad1(2001,Wang,98.5,563.5);//定义Graduate类对象grad1

  Student *pt=&stud1;//定义指向Student类对象的指针并指向stud1

  pt->display( ); //调用stud1.display函数

  pt=&grad1; //指针指向grad1

  pt->display( ); //调用grad1.display函数

}

 

很多读者会认为: 在派生类中有两个同名的display成员函数,根据同名覆盖的规则,被调用的应当是派生类Graduate对象的display函数,在执行Graduate::display函数过程中调用Student::display函数,输出num,name,score,然后再输出pay的值。

 

事实上这种推论是错误的,先看看程序的输出结果:

num:1001

name:Li

score:87.5

num:2001

name:wang

score:98.5

并没有输出pay的值。

 

问题在于pt是指向Student类对象的指针变量,即使让它指向了grad1,但实际上pt指向的是grad1中从基类继承的部分。

 

通过指向基类对象的指针,只能访问派生类中的基类成员,而不能访问派生类增加的成员。所以pt->display()调用的不是派生类Graduate对象所增加的display函数,而是基类的display函数,所以只输出研究生grad1num,name,score3个数据。

 

如果想通过指针输出研究生grad1pay,可以另设一个指向派生类对象的指针变量ptr,使它指向grad1,然后用ptr->display()调用派生类对象的display函数。但这不大方便。

 

通过本例可以看到: 用指向基类对象的指针变量指向子类对象是合法的、安全的,不会出现编译上的错误。但在应用上却不能完全满足人们的希望,人们有时希望通过使用基类指针能够调用基类和子类对象的成员。

 


版权声明:本文为博主原创文章,未经博主允许不得转载。

C++笔记:派生类到基类转换到可访问性

要确定到基类的转换是否可访问,可以考虑基类的public成员是否可访问,如果可以,转换是可以访问的,否则,转换是不可访问的。...
  • liufei_learning
  • liufei_learning
  • 2014年03月20日 06:43
  • 4496

C++中派生类和基类的转换和访问控制

区分“派生类对象”和“派生类”对基类成员的访问权限。 l “派生类对象”对基类成员的访问权限:    (1)对于公有继承,只有基类的公有成员可以被“派生类对象”访问,其他(保护和私有)成员不能被访问。...
  • KingCat666
  • KingCat666
  • 2015年04月06日 21:58
  • 1084

派生类,基类类型转换

派生类,基类类型转换
  • kturing
  • kturing
  • 2015年06月19日 10:26
  • 1163

C++基类和派生类的赋值

点击打开链接 在C/C++中,经常会发生数据类型转换,例如整型数据可以赋值给浮点型变量,在赋值之前,先把整型数据转换为浮点型;反过来,浮点型数据也可以赋值给整型变量。 数据类型转换的前...
  • chengonghao
  • chengonghao
  • 2016年04月05日 09:49
  • 1431

派生类和基类的关系

派生类和基类的关系C++一个主要目标是提供代码重用,类继承是实现该目标的重要途径之一。从一个类派生出另一个类时,原始类称为基类,继承类称为派生类。 派生类和基类的关系: 1. 派生类对象存储了基类...
  • white__bear
  • white__bear
  • 2015年12月03日 22:30
  • 3176

C++-继承:基类与派生类的关系

成员函数的重定义和名字隐藏基类的数据成员和成员函数在派生类中都有一份拷贝,派生类能够直接访问从基类继承而来的public和protected成员,且只能够通过这两类成员访问从基类继承而来的privat...
  • ko_tin
  • ko_tin
  • 2017年02月23日 18:29
  • 274

派生类和基类的函数调用

这篇文章举了一个简单的例子说明派生类和基类在虚函数和普通函数的问题; 首先声明派生类和基类,并进行定义,如下所示: 声明部分(Header.h): class FATHER { public: vo...
  • GK_2014
  • GK_2014
  • 2015年05月13日 22:57
  • 1390

基类中this指针和派生类对象的关系,同名隐藏原则和作用域的示例

最近在分析cocos2d-x启动代码的时候,不小心看到单例的程序,
  • imcabbage
  • imcabbage
  • 2016年03月21日 10:58
  • 505

派生类和基类中的成员变量名相同(转)

源地址 当派生类中的成员变量和基类中同名,那么与函数同名一样,基类中的同名变量会被隐藏。也就是通过派生类对象无法访问基类的同名变量。例一:class base { public: int a...
  • batuwuhanpei
  • batuwuhanpei
  • 2016年08月02日 15:13
  • 645

与基类对象和派生类对象相关的赋值兼容问题

派生类对象间的赋值操作依据下面的原则: n(1)如果派生类有自己的赋值运算符的重载定义,即按该重载函数处理。 n(2)派生类未定义自己的赋值操作,而基类定义了赋值操作,则系统自动定义派生类赋值操作...
  • jiangbingbo123
  • jiangbingbo123
  • 2015年07月26日 09:53
  • 535
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:派生类与基类的转换
举报原因:
原因补充:

(最多只允许输入30个字)