C++子类 父类的相互转换 和 虚函数
来源:互联网 发布:指南针软件卸载 编辑:程序博客网 时间:2024/06/03 22:59
今天在程序中遇到一个问题,关于子类 父类的强制转换的。查了下网络,大概弄懂了些,记录下来作为笔记。
先看一个例子
【引自雁南飞的博客】在C++的世界中有这样两个概念,向上类型转换,向下类型转换,分别描述的是子类向基类和基类向子类的强制类型转换。
向上强制类型转换
切割:覆盖方法和子类数据丢失的现象生成切割(slice)。
#include "stdafx.h"#include <iostream>using namespace std;class Base{public:int b;virtual void Test(){cout << "base" <<endl;}};class Derived:public Base{public:int tt;int d;virtual void Test(){cout << "derived" <<endl;}virtual void check(){cout << "derived check" <<endl;}};int main(){Derived d;d.d = 1;d.tt = 2;Base b = d;//直接赋值(产生切割)b.Test();Base& b2 = d;//使用引用赋值(不产生切割)b2.Test();Base* b3 = &d;//使用指针赋值(不产生切割)b3->Test();//b3->check();system("PAUSE");return 1;}
然后我们看监视的结果:
(1)对象层面:
在对象上,我们可以看到所有的转换都出现了阉割(毋庸置疑的,由于子类的内存比父类大,转换为父类肯定会“丢失”信息,只会保留相同的东西)。另外由于虚函数的原因,引用和指针都指向子类,而直接对象的转换则直接指向了父类。
(2)地址层面
从地址上看,采用引用和指针的转换地址和原始子类一致,直接对象的转换则地址 被改变减少了16个字节(为什么? 没搞为什么事减? 为什么是16? 希望大神能解答).
因此,我们得出结论,在向上强制转换过程中,使用指针和引用不会造成切割,而使用直接赋值会造成切割。
向下强制类型转换
使用dynamic_cast进行向下强制类型转换。使用此关键字有一下几个条件:
1、源类型必须有虚函数;
2、必须打开编译器的RTTI开关(vc6: progect-> settings -> c/c++ tab ->category[c++ language]-> Enable RTTI);
3.必须有继承关系。
using namespace std;
class CPoint
{
public:
virtual void f(){cout << "CPoint::f" <<endl;}
};
class CPoint3D : public CPoint
{
public:
virtual void f(){cout << "CPoint3D::f" <<endl;}
};
int main()
{
CPoint point,*pPoint;
CPoint3D point3D,*pPoint3D;
//子类向父类类型转换,直接强制转换就可以了,但实际仍然指向子类对象
pPoint = (CPoint*)&point3D;
pPoint->f(); //调用的仍然是子类的函数,这便是虚函数的魅力所在
//父类向子类类型转换,要用dynamic_cast
pPoint3D = dynamic_cast(pPoint);
pPoint->f(); //pPoint实际指向一个CPoint3D对象,故可以正确转换
pPoint3D = dynamic_cast(&point);
cout << (int*)pPoint3D << endl; //&point指向的不是一个CPoint3D对象,返回值为NULL
return 0;
}
运行结果为:
CPoint3D::f
CPoint3D::f
00000000
这个问题牵扯到c++的对象模型。一般认为子类对象大小>=父类对象大小。为什么?因为子类可以扩展父类,可以增加成员变量。如果一个子类增加了成员变量,那么它的对象的内存空间会大于父类对象。这时一个实际指向父类的指针,如果被强制转化为子类对象指针,当使用这个指针时可能会导致越界访问非法内存。相反,为何子类指针可以转换为父类指针?因为父类指针需要的,子类对象都有,不会出现非法内存访问。
这就是dynamic_cast不一定成功的原因。如果一个实际指向子类对象的指针被转换成了父类指针,然后再用dynamic_cast转换回来,一定能成功,而一个实际指向父类对象的指针,被dynamic_cast转换为子类指针,一定会失败。
因此,我们可以使用dynamic_cast来判断两个类是否存在继承关系。
- C++子类 父类的相互转换 和 虚函数
- 子类和父类的相互转换
- C++中子类和父类之间的相互转换
- 父类和子类的相互转换及父类调用子类的方法
- C#中子类与父类的相互转换
- C#中子类与父类的相互转换
- C#中子类与父类的相互转换
- 父类子类指针相互转换问题
- 父类子类指针相互转换问题
- java学习笔记:java的多态,子类和父类的相互转换,父类引用指向子类的对象
- C++中子类和父类之间的相互转化
- java父类和子类的相互访问
- iframe的父类 子类相互调用
- 子类父类变量的相互赋值
- JAVA中子类与父类相互转换
- 子类和父类的构造函数
- 关于继承(子类对象与父类对象【相互转换】的过程)
- void*和类成员函数指针的相互转换
- Linux init程序分析(续)
- ios_oc @property和@synthesize以及属性介绍
- Oracle中的wmsys.wm_concat
- Android 创建快捷方式图标
- X Window System介绍
- C++子类 父类的相互转换 和 虚函数
- JMF网页视频语音聊天
- 极速理解设计模式系列:2.工厂方法模式(Factory Method Pattern)
- 【Visual Studio】VS2012中利用Visual Assist X添加文件头和函数注释
- 拷贝构造函数
- 微信公众平台SDK! Senparc.Weixin.MP.dll(资料整理)
- android 电池(一):锂电池基本原理篇
- 第一天:主要实现解析xml文件和生成xml文件
- explode() 函数的应用