C++基类和派生类之间的转换
本文讲解内容的前提是派生类继承基类的方式是公有继承,关键字public
以下程序为讲解用例。
#include<iostream>
using namespace std; class A
{
public:
A(int m1, int n1):m(m1), n(n1){}
void display();
private:
int m;
int n;
}; void A::display()
{
cout << "m = " << m << endl;
cout << "n = " << n << endl;
} class B :public A
{
public:
B(int m1, int n1, int p1) :A(m1, n1), p(p1){}
void display();
private:
int p;
}; void B::display()
{
A::display();
cout << "p = " << p << endl;
} void print1(A& a)
{
a.display();
} void print2(B& b)
{
b.display();
} void print3(A a)
{
a.display();
} void print4(B b)
{
b.display();
} int main()
{
A a(, );
// a.display();
B b(, , );
// b.display(); A * pa;
B * pb;
pa = &a;
// pa->display();
pb = &b;
// pb->display(); // pa = &b;
// pa->display(); // pb = &a; //错误。派生类指针不能指向基类对象。 // print1(b);
// print2(a); //错误。不能用基类对象给派生类引用赋值。
// print3(b);
// print4(a); //错误。不能用基类对象给派生类对象赋值。 // pb = pa; //不能用基类指针给派生类指针赋值。 pb = (B*)pa; //可以强制转换,但是非常不安全。
pb->display(); //出现安全问题,p无法访问,因为a中没有p成员
system("pause");
return ;
}
切记:派生类对象是基类对象,派生类中包含有基类的成员。基类对象不是派生类对象,它不能包含派生类型的成员。
/**************派生类到基类的转化**************/
1。派生类对象地址赋值给基类指针
main函数中执行以下代码
A a(, );
// a.display();
B b(, , );
// b.display(); A * pa;
// B * pb;
// pa = &a;
// pa->display();
// pb = &b;
// pb->display(); pa = &b;
pa->display(); //会输出 10 20
pa为基类指针,指向派生类对象是合法的,因为派生类对象也是基类对象。语句会输出派生类对象中基类部分。
注意:这里并不会调用派生类的display函数,调用的是基类的display函数,因为指针pa是基类指针,编译器在编译阶段只知道pa的类型。如果要实现调用派生类的display函数,
需要用到虚函数实现多态性。之后的文章会讲到。
进一步解释一下编译时和运行时的区别。
编译时编译器能知道pa的类型为A *,但是不知道它指向了哪个对象,假如有以下语句
A a(, );
B b(, , );
A* pa;
int number;
cin >> number;
if (number >= )
pa = &a;
else
pa = &b;
pa指向的对象类型依赖于输入,运行时才输入,所以编译器是没有办法知道pa指向哪个类型的。
2.派生类对象赋值给基类引用
/**引用跟指针基本没有区别,引用本质上是指针,是个指针常量,具体可以参照我的另一篇C++中的引用和指针的联系和区别**/
main函数中执行以下代码
A a(, );
B b(, , );
print1(b); //会输出 10 20
形参为基类引用,实参为派生类对象,派生类对象也是基类对象,可以赋值给基类引用。输出派生类中基类部分。
注意:此时对象本身并未复制,b仍然是派生类对象,前面说过了引用就是一个指针。
3.派生类对象赋值给基类对象。
A a(, );
B b(, , );
print3(b);
派生类对象基类部分被复制给形参。
注意:实际上没有从派生类对象到基类对象的直接转换。对基类对象的赋值或初始化,实际上在调用函数,初始化时调用构造函数,赋值时调用赋值操作符。
/********************基类到派生类的转化******************/
切记:这种转换有可能引发严重的安全问题,编写代码时不要使用。没有基类到派生类的自动转换,原因在于基类对象只能是基类对象,不能包含派生类型的成员。
如果允许用基类对象给派生类对象赋值,那么就可以试图使用该派生类对象访问不存在的成员。
A a(, );
B b(, , );
A * pa;
B * pb;
// print2(a); //错误。不能用基类对象给派生类引用赋值。
// print4(a); //错误。不能用基类对象给派生类对象赋值。
// pb = &a; //错误。派生类指针不能指向基类对象。 pa = &a;
pb = &b; //pb = pa; //错误。不能用基类指针给派生类指针赋值。 pb = (B*)pa; //可以强制转换,但是非常不安全。
pb->display(); //出现安全问题,p无法访问,因为a中没有p成员
注意到我们使用强制转换时,当派生类添加了基类中不存在的成员时,会出现安全问题。
pb->display();会调用派生类的display函数,但是它指向的内存是基类对象a的内存,p不存在。会出现严重后果。
C++基类和派生类之间的转换的更多相关文章
- (转) C++中基类和派生类之间的同名函数的重载问题
		
下面有关派生类与基类中存在同名函数 fn: class A { public: void fn() {} void fn(int a) {} }; class B : public A { publi ...
 - C++:基类与派生类对象之间的赋值兼容关系
		
4.5 基类与派生类对象之间的赋值兼容关系 在一定条件下,不同类型的数据之间可以进行类型转换,例如可以将整型数据赋给双精度型变量. 在赋值之前,先把整型数据转换为双精度型数据,然后再把它双精度型变量. ...
 - C++学习21 基类和派生类的赋值
		
在C/C++中,经常会发生数据类型转换,例如整型数据可以赋值给浮点型变量,在赋值之前,先把整型数据转换为浮点型:反过来,浮点型数据也可以赋值给整型变量. 数据类型转换的前提是,编译器知道如何对数据进行 ...
 - OOP1(定义基类和派生类)
		
面向对象程序设计基于三个基本概念:数据抽象,继承和动态绑定 数据抽象是一种依赖于接口和实现分离的编程技术.继承和动态绑定对程序的编号有两方面的影响:一是我们可以更容易地定义与其它类相似但不完全相同的类 ...
 - 详解C++中基类与派生类的转换以及虚基类
		
很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中 ...
 - 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)
		
[源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...
 - c++中基类与派生类中隐含的this指针的分析
		
先不要看结果,看一下你是否真正了解了this指针? #include<iostream> using namespace std; class Parent{ public: int x; ...
 - 基类和派生类--this
		
基类指针在程序运行的时候的确指向的是一个派生类的对象,但指针的类型仍然是基类指针.C++是一种强类型语言,因此不能用基类指针类型的指针直接调用派生类:而且,同一个类可能有多种不同的派生类,因此不知道实 ...
 - C++:基类和派生类
		
4.1 派生类的声明 继承实例如下: class Person{ //声明基类Person public: void print() { cout<<"name:"&l ...
 
随机推荐
- 然爸读书笔记(2013-4)----打造facebook
			
扎克伯格的真实一面 (1)在公司内部知无不言,扎克伯格在公司内部问答时间.尽可能回答员工的任何问题,保持足够的透明度. (2)员工只有做到对外守口如瓶,我们才能做到对内知无不言. (3)faceboo ...
 - linux下nginx的安装
			
一.安装nginx 1.在nginx官方网站下载一个包,下载地址是:http://nginx.org/en/download.html 2.WinSCP(ftp上传工具).exe FT ...
 - UINavigationController 总结
			
一 . UINavigationBar 1.获取 UINavigationBar 对象: [UINavigationBar appearance] ,可以通过该方法对全部 navigation 进行设 ...
 - CROSS APPLY vs OUTER APPLY
			
Apply 工作原理: Apply操作符让符合查询的每一条记录都调用一次TVF函数,并将结果与原数据表的记录内容一起展开. Apply操作符定义在From子句内,使用方式与Join操作符类 ...
 - query specified join fetching, but the owner of the fetched association was not present in the select list
			
报标题的错误,是因为在 select count的时候,不需要fetch 所以在取完count以后,再把fetch加进去,变成left join fetch /** * 请把jhql以o为返回对象, ...
 - maven 解决 Eclipse is running in a JRE, but a JDK is
			
解决安装了maven插件的myeclipse每次开启报错 The Maven Integration requires that Eclipse be running in a JDK, becaus ...
 - Google Play市场考察报告
			
考察了Google Play日本市场的10款应用,考察的重点在于每个App有什么亮点,盈利模式在哪里.本文并不是App的功能介绍. (1)恋爱文集[文库类应用] 该应用收录了一些恋爱文章,其主要受众是 ...
 - lsof命令总结
			
1.lsof 简介 lsof 是 linux 下的一个非常实用的系统级的监控.诊断工具.它的意思是 List Open Files,很容易你就记住了它是 “ls + of”的组合~它可以用来列出被各种 ...
 - html--offsetLeft,Left,clientLeft的关键--动态获取计算元素位置关系
			
动态计算元素位置关系的时候,必备... http://www.cnblogs.com/panjun-Donet/articles/1294033.html
 - thinkphp多表关联并且分页
			
$db_prefix = C('DB_PREFIX'); $Model = new Model(); $data = $Model->table("{$db_prefix}ordern ...