C++基类与派生类的转换
具体表现在以下几个方面: 派生类对象可以向基类对象赋值。 可以用子类(即公用派生类)对象对其基类对象赋值。如 A a1; //定义基类A对象a1 B b1; //定义类A的公用派生类B的对象b1 a1=b1; //用派生类B对象b1对基类对象a1赋值 在赋值时舍弃派生类自己的成员。
实际上,所谓赋值只是对数据成员赋值,对成员函数不存在赋值问题。请注意: 赋值后不能企图通过对象a1去访问派生类对象b1的成员,因为b1的成员与a1的成员是不同的。
假设age是派生类B中增加的公用数据成员,分析下面的用法: a1.age=23;//错误,a1中不包含派生类中增加的成员 b1.age=21; //正确,b1中包含派生类中增加的成员 应当注意,子类型关系是单向的、不可逆的。B是A的子类型,不能说A是B的子类型。
只能用子类对象对其基类对象赋值,而不能用基类对象对其子类对象赋值,理由是显然的,因为基类对象不包含派生类的成员,无法对派生类的成员赋值。同理,同一基类的不同派生类对象之间也不能赋值。 派生类对象可以替代基类对象向基类对象的引用进行赋值或初始化。 如已定义了基类A对象a1,可以定义a1的引用变量: A a1; //定义基类A对象a1 B b1; //定义公用派生类B对象b1 A& r=a1; //定义基类A对象的引用变量r,并用a1对其初始化 这时,引用变量r是a1的别名,r和a1共享同一段存储单元。也可以用子类对象初始化引用变量r,将上面最后一行改为 A& r=b1;//定义基类A对象的引用变量r,并用派生类B对象b1//对其初始化 或者保留上面第3行“A& r=a1;”,而对r重新赋值: r=b1;//用派生类B对象b1对a1的引用变量r赋值
注意: 此时r并不是b1的别名,也不与b1共享同一段存储单元。它只是b1中基类部分的别名,r与b1中基类部分共享同一段存储单元,r与b1具有相同的起始地址。 如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类对象。如有一函数 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,float s,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,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//声明公用派生类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中从基类继承的部分。转载请注明圣安娜娱乐http://www.leruntoys.com
C++基类与派生类的转换的更多相关文章
- 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)
[源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...
- C++基类和派生类之间的转换
本文讲解内容的前提是派生类继承基类的方式是公有继承,关键字public 以下程序为讲解用例. #include<iostream> using namespace std; class A ...
- 详解C++中基类与派生类的转换以及虚基类
很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中 ...
- (转) C++中基类和派生类之间的同名函数的重载问题
下面有关派生类与基类中存在同名函数 fn: class A { public: void fn() {} void fn(int a) {} }; class B : public A { publi ...
- C++学习21 基类和派生类的赋值
在C/C++中,经常会发生数据类型转换,例如整型数据可以赋值给浮点型变量,在赋值之前,先把整型数据转换为浮点型:反过来,浮点型数据也可以赋值给整型变量. 数据类型转换的前提是,编译器知道如何对数据进行 ...
- C++:基类与派生类对象之间的赋值兼容关系
4.5 基类与派生类对象之间的赋值兼容关系 在一定条件下,不同类型的数据之间可以进行类型转换,例如可以将整型数据赋给双精度型变量. 在赋值之前,先把整型数据转换为双精度型数据,然后再把它双精度型变量. ...
- c++,派生类对象可以对基类赋值,基类对派生类不可以赋值
派生类对象可以对基类对象赋值,赋值时属于派生类独有的部分就舍弃不用. #include <iostream> using namespace std; class DemoA { publ ...
- OOP1(定义基类和派生类)
面向对象程序设计基于三个基本概念:数据抽象,继承和动态绑定 数据抽象是一种依赖于接口和实现分离的编程技术.继承和动态绑定对程序的编号有两方面的影响:一是我们可以更容易地定义与其它类相似但不完全相同的类 ...
- c++中基类与派生类中隐含的this指针的分析
先不要看结果,看一下你是否真正了解了this指针? #include<iostream> using namespace std; class Parent{ public: int x; ...
- 基类和派生类--this
基类指针在程序运行的时候的确指向的是一个派生类的对象,但指针的类型仍然是基类指针.C++是一种强类型语言,因此不能用基类指针类型的指针直接调用派生类:而且,同一个类可能有多种不同的派生类,因此不知道实 ...
随机推荐
- php常见验证
/** * 文件上传 * @param $file 要上传的文件 * @param $size 大小设置 * @param $ext 文件类型 * @return bool 是否上传成功 */func ...
- Python爬虫系列-Selenium详解
自动化测试工具,支持多种浏览器.爬虫中主要用来解决JavaScript渲染的问题. 用法讲解 模拟百度搜索网站过程: from selenium import webdriver from selen ...
- http客户端与浏览器的区别
两者区别:浏览器对http响应头会进行特定处理(如自动读取本地缓存.设置cookie等),而http客户端(如crul)可能没有像浏览器那样的处理,某些封装程度高的http客户端,可能会有. 同一个文 ...
- 【转】centos中service命令与/etc/init.d的关系以及centos7的变化
centos中service命令与/etc/init.d的关系 service httpd start 其实是启动了存放在/etc/init.d目录下的脚本. 但是centos7的服务管理改规则了.C ...
- python基本操作(五)
if 判断 if 条件: 代码1 代码2 代码3 代码块(同一缩进级别的代码,例如代码1.代码2和代码3是相同缩进的代码,这三个代码组合在一起就是一个代码块,相同缩进的代码会自上而下的运行) cls ...
- perl-basic-数据类型&引用
我觉得这一系列的标题应该是:PERL,从入门到放弃 USE IT OR U WILL LOSE IT 参考资料: https://qntm.org/files/perl/perl.html 在线per ...
- JavaScript日期时间格式化函数
这篇文章主要介绍了JavaScript日期时间格式化函数分享,需要的朋友可以参考下 这个函数经常用到,分享给大家. 函数代码: //格式化参数说明: //y:年,M:月,d:日,h:时,m分,s:秒, ...
- [转载]ExtJs4 笔记(1) ExtJs大比拼JQuery:Dom文档操作
出处:[Lipan] (http://www.cnblogs.com/lipan/) 现在主流的JS框架要数ExtJs和JQuery应用的比较广泛.JQuery属于轻量级的,一般做网站应用比较常见,可 ...
- ogre3D程序实例解析1-平移旋转与缩放
接着上篇写 http://www.cnblogs.com/songliquan/p/3294902.html 旋转 这里有必要看一下关于旋转的源代码: virtual void pitch(co ...
- windows系统使用的误区
1.软件不要装在c盘,影响系统运行速度. 软件c盘不会影响系统运行,会提高软件运行速度 PS:前提条件:C盘有足够的空余空间(50G以上). 大多数软件安装默认路径在C盘的原因是不知道电脑分区的情况, ...