派生类到基类的转换 和基类到派生类的转换
一、 基类与派生类的转换
3种继承方式(公用、保护、私有继承)中,公用派生类才是基类真正的子类型,它完整地继承了基类的功能。
不同类型数据之间在一定条件下可以进行类型的转换。基类与派生类对象之间是否也有赋值兼容的关系,可否进行类型间的转换?回答是可以的。基类与派生类对象之间有赋值兼容关系,由于派生类中包含从基类继承的成员,因此可以将派生类的值赋给基类对象,在用到基类对象的时候可以用其子类对象代替 。
注意:有的数据类型是不可转换的;有的转换是不可逆的。
1、派生类对象可以向基类对象赋值。
可以用子类(即公用派生类)对象对其基类对象赋值。
如:
A al; //定义基类A对象al
B bl; //定义类A的公用派生类B的对象bl
a1=b1; //用派生类B对象bl对基类对象al赋值
实际上,所谓赋值只是对数据成员赋值,对成员函数不存在赋值问题。
注意:
1、赋值后不能企图通过对象a1去访问派生类对象bl的成员,因为bl的成员与al的成员是不同的。假设ase是派生类B中增加的公用数据成员,分析下面的用法:
a1.age=23;//错误,al中不包含派生类中增加的成员
b1.age=21;//正确,b1中包含派生类中增加的成员
2、子类型关系是单向的、不可逆的。B是A的子类型,不能说A是B的子类型。只能用子类对象对其基类对象赋值,而不能用基类对象对其子类对象赋值,理由是显然的,因为基类对象不包含派生类的成员,无法对派生类的成员赋值。同理,同一基类的不同派生类对象之间也不能赋值。
2、派生类对象可以替代基类对象向基类对象的引用进行赋值或初始化 。
如已定义了基类A对象a1,可以定义a1的引用:
A al; //定义基类A对象al
B bl; //定义公用派生类B对象bl
A&r=al;//定义基类A对象的引用变量r,并用a1对其初始化
引用r是al的别名,r和a1共享同一段存储单元。可以用子类对象初始化引用r,将上面最后一行改为:
A&r=bl;//定义基类A对象的引用变量r,并用派生类B对象b1对其初始化或者保留上面第3行“A&r=al;”,而对r重新赋值:
r=bl; //用派生类B对象bl对a1的引用变量r赋值
注意 :此时r并不是bl的别名,也不与bl共享同一段存储单元。它只是b1中基类部分的别名,r与bl中基类部分共享同一段存储单元,r与b1具有相同的起始地址。
3、如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类对象。
如有一函数fun:
void fun(A&r) //形参是类A的对象的引用
{ cout<<r.num<<endl;}//输出该引用所代表的对象的数据成员num
函数的形参是类A的对象的引用变量,本来实参应该为A类的对象。由于子类对象与派生类对象赋值兼容,派生类对象能自动转换类型,在调用fun函数时可以用派生类B的对象bl作实参: fun(b1);
输出类B的对象bl的基类数据成员num的值。
在fun函数中只能输出派生类中基类成员的值 。
4、派生类对象的地址可以赋给指向基类对象的指针变量,也就是说,指向基类对象的指针变量也可以指向派生类对象。
例10 定义一个基类Student(学生),再定义Student类的公用派生类Graduate(研究生),用指向基类对象的指针输出数据。
本例主要是说明用指向基类对象的指针指向派生类对象,为了减少程序长度,在每个类中只设很少成员。学生类只设num(学号),name(名字)和score(成绩)3个数据成员,Graduate类只增加一个数据成员pay(工资) :
#include <string>
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,float s)//定义构造函数
{ 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 //声明公用派生类Graduale
{ public:
Graduate(int,string,float,float);//声明构造函数
void display(); //声明输出函数
private:
float pay; }; //工资
void Graduate::display() //定义输山函数
{ Student::display(); //调用Student类的display函数
cout<<"pay="<<pay<<endl; }
Graduate::Graduate(int n,string nam,float s,float p):Student(n,nam,s),pay(p){}
//定义构造函数int main()
{ Student stud1(1001,"Li",87.5); //定义Student类对象stud1
Graduate grad1(2001,"Wang",98.5,563.5);//定义Graduate类对象grad1
Student *pt=&stud1; //定义指向Student类对象的指针并指向studl
pt->display(); //调用studl.display函数
pt=&grad1; //指针指向gradl
pt->display(); //调用gradl.display函数
return 0; }程序的输出结果:
num:1001
name:Li
score:87.5
num:2001
nume:wang
score:98.5
为什么没有输出pay的值?
通过本例可以看到: 用 指向基类对象的指针变量指向子类对象是合法的、安全的,不会出现编译上的错误。但在应用上却不能完全满足人们的希望,人们有时希望通过使用基类指针能够调 用基类和子类对象的成员。如果能做到这点,程序人员会感到方便。在下一章就要解决这个问题。办法是使用虚函数和多态性。
派生类到基类的转换 和基类到派生类的转换相关推荐
- 写出一个类People,并由该类做基类派生出子类Employee和Teacher
写出一个类People,并由该类做基类派生出子类Employee和Teacher.其中People 类具有name.age两个保护成员变量,分别为String类型.整型,且具有公有的getAge成员函 ...
- 单例模式-基类单例。。用于其他单例的派生
首先是继承方式,为了进行单例的派生,需要将基类的构造函数以及拷贝赋值函数设置为protected成员 template <class T> class Singleton { privat ...
- 设计一个Windows应用程序,要求如下: 构造一个产品基类。 分别定义家电、日用百货、衣服等派生类,具体要求有不同的特征和行为。 定义一个泛型货架类,约束参数类型为产品
设计一个Windows应用程序,要求如下: 构造一个产品基类. 分别定义家电.日用百货.衣服等派生类,具体要求有不同的特征和行为. 定义一个泛型货架类,约束参数类型为产品类.该泛型的货架类包括一个泛型 ...
- Java基类共同属性设置_多选择基类的访问属性-Java初学笔记
多选择基类的访问属性 你现在知道在定义类的访间属性时可用的选择项,你希望使用这些类定义子类.你知道在类继承上这些属性所具有的效果,但是你如何决定到底应该使用哪一个呢? 这里没有死板和现成的规则,你选择 ...
- 定义一个三角形类(TRI)及其派生类三角柱体类(COL)。其中三角形类可以计算三角形的面积和周长;三角柱体类可以计算柱体的体积和表面积。其具体要求如下: (1)TRI的成员如下: 私有数据成员
题目要求: 定义一个三角形类(TRI)及其派生类三角柱体类(COL).其中三角形类可以计算三角形的面积和周长:三角柱体类可以计算柱体的体积和表面积.其具体要求如下: (1)TRI的成员如下: 私有数据 ...
- 虚基类、虚函数和纯虚基类
http://blog.csdn.net/lovemysea/article/details/5298589 首先看一个例子: class Base { public: virtual voi ...
- 编码字典类特征、使用sklearn的DictVectorizer方法将字典组成的列表转换成向量、详解及实战
编码字典类特征.使用sklearn的DictVectorizer方法将字典组成的列表转换成向量.详解及实战 sklearn.feature_extraction.DictVectorizer() 把字 ...
- File类与IO流知识总结(三):缓冲流、转换流、序列化流
一 :缓冲流 在上篇文章中学习了基本的一些流,作为IO流的入门,而现在我们要见识一些更强大的流.比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等.这些功能更为强大的流, ...
- java派生类属例子_【备考】带你认识相关类属vs派生类属!
原标题:[备考]带你认识相关类属vs派生类属! 关于下位学习中的相关类属和派生类属总有一些同学在做题过程中出现疑惑,做题也是错误率较高.究其原因就是同学们掌握二者概念的时候,很多人都是用例子来记住概念 ...
最新文章
- 【数论基础】模运算详解及其应用
- HDU 2037 今年暑假不AC【贪心】
- 【经济法常识转摘】借款人逾期不还钱,利率如何确定?
- 为XPath自定义函数(因为XPath1.0的函数非常有限)[附源代码下载]
- linux安装lrzsz,并使用rz sz 命令
- 拦截游戏窗口被移动_Ruined King官网版-拳头rpg Ruined King游戏最新版下载v1.0
- hadoop常用的端口配置
- JupyterHub on Kubernetes绘图支持软件
- 【脑电信号】基于matlab SVM分期睡眠监测【含Matlab源码 611期】
- mtk 充电出错问题
- 简单工具之 ---- IP地址快速修改脚本
- 修改Android应用名称
- 苹果CMS火车头采集发布模块教程
- 老瞎眼 pk 小鲜肉
- kafka 中如何保证数据消息不丢失
- 爬取热榜数据,通过Qt界面显示,代码可直接运行(python3经典编程案例)
- 生成对抗网络——原理解释和数学推导
- Maxima 矩阵及矢量运算 1
- 企业微信如何创建待办事项?
- sql 数据库创建及建表,
热门文章
- 【Android 插件化】Hook 插件化框架 ( 反射工具类 | 反射常用操作整理 )
- 【Google Play】App Bundle 使用详解 ( 简介 | 应用内更新 | 即时更新 | 灵活更新 )
- 【CMake】CMake 引入 ( Android Studio 创建 Native C++ 工程 | C/C++ 源码编译过程 | Makefile 工具 | CMake 引入 )
- 【集合论】关系闭包 ( 关系闭包相关定理 )
- [Spring cloud 一步步实现广告系统] 15. 使用开源组件监听Binlog 实现增量索引准备...
- 二叉树的链式存储结构--二叉链表
- delphi XE 下打开内存泄漏调试功能
- servlet中的几个路径有关的方法
- C程序多线程同时画圆画方
- 第13章 Kotlin 集成 SpringBoot 服务端开发(1)