博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
dynamic_cast报错 异常
阅读量:2398 次
发布时间:2019-05-10

本文共 8215 字,大约阅读时间需要 27 分钟。

 转载请标明是引用于

 代码:

UnHandled exception at x0 in :

出错的地方是:

 

class IReferenceCounted{public:	//!!!!!! 大家注意了.这里的virtual不能去掉,去掉就会报错,报错信息下面	/*	1>main.cpp	1>c:\documents and settings\administrator\桌面\test_dynamic_cast\main.cpp(117) : error C2683: “dynamic_cast”:“IGUIBase”不是多态类型	1>c:\documents and settings\administrator\桌面\test_dynamic_cast\main.cpp(100) : 参见“IGUIBase”的声明	因为加上了virtaul后使IReferenceCounted成为了多态类,如果不在这里加也可以,比如可以写一个带virtual的函数 fff()	*/	virtual ~IReferenceCounted()	{	}	//virtual void  fff(){};};class IObject : public IReferenceCounted{};class IEventReceiver{	};class IGUIBase : public IEventReceiver,public IObject{};class CheckBoxGroup : public IObject{};int main() {	IGUIBase *pChild = new IGUIBase();	// 这里是运行会报错的地方	/*	解决方法是:	工程属性->C/C++->语言->启用运行时类型信息 是	*/	if (dynamic_cast
(pChild)) { printf("dynamic_cast of pChild is exist\n"); }

 解决方法是:

工程属性->C/C++->语言->启用运行时类型信息 是

 

参考下面文章:

 

dynamic_cast运算符,应该算是四个里面最特殊的一个,因为它涉及到编译器的属性设置,而且牵扯到的面向对象的多态性跟程序运行时的状态也有关系,所以不能完全的使用传统的转换方式来替代。但是也因此它是最常用,最不可缺少的一个运算符。

与一样,dynamic_cast的转换也需要目标类型和源对象有一定的关系:继承关系。 更准确的说,dynamic_cast是用来检查两者是否有继承关系。因此该运算符实际上只接受基于类对象的指针和引用的类转换。从这个方面来看,似乎dynamic_cast又和是一致的,但实际上,它们还是存在着很大的差别。

还是用代码来解释,让编译器来说明吧。

以下是说明的代码:

/// cast_operator_comparison.cpp                                                      // Language:   C++                   // Complier:    Visual Studio 2010, Xcode3.2.6 // Platform:    MacBook Pro 2010// Application:  none  // Author:      Ider, Syracuse University  ider.cs@gmail.com///#include 
#include
#include
using namespace std;class Parents{public: Parents(string n="Parent"){ name = n;} virtual ~Parents(){} virtual void Speak() { cout << "\tI am " << name << ", I love my children." << endl; } void Work() { cout << "\tI am " << name <<", I need to work for my family." << endl;; }protected: string name;};class Children : public Parents{public: Children(string n="Child"):Parents(n){ } virtual ~Children(){} virtual void Speak() { cout << "\tI am " << name << ", I love my parents." << endl; } /* **Children inherit Work() method from parents, **it could be treated like part-time job. */ void Study() { cout << "\tI am " << name << ", I need to study for future." << endl;; } private: //string name; //Inherit "name" member from Parents};class Stranger {public: Stranger(string n="stranger"){name = n;} virtual ~Stranger(){} void Self_Introduce() { cout << "\tI am a stranger" << endl; } void Speak() { //cout << "I am a stranger" << endl; cout << "\tDo not talk to "<< name << ", who is a stranger." << endl; }private: string name;};

 

int main() {	/******* cast from child class to base class *******/	cout << "dynamic_cast from child class to base class:" << endl;	Children * daughter_d = new Children("Daughter who pretend to be my mother");	Parents * mother_d = dynamic_cast
(daughter_d); //right, cast with polymorphism mother_d->Speak(); mother_d->Work(); //mother_d->Study(); //Error, no such method cout << "static_cast from child class to base class:" << endl; Children * son_s = new Children("Son who pretend to be my father"); Parents * father_s = static_cast
(son_s); //right, cast with polymorphism father_s->Speak(); father_s->Work(); //father_s->Study(); //Error, no such method cout << endl; /******* cast from base class to child class *******/ cout << "dynamic_cast from base class to child class:" << endl; Parents * father_d = new Parents("Father who pretend to be a my son"); Children * son_d = dynamic_cast
(father_d); //no error, but not safe if (son_d) { son_d->Speak(); son_d->Study(); } else cout << "\t[null]" << endl; cout << "static_cast from base class to child class:" << endl; Parents * mother_s = new Parents("Mother who pretend to be a my daugher"); Children * daughter_s = static_cast
(mother_s); //no error, but not safe if (daughter_s) { daughter_s->Speak(); daughter_s->Study(); } else cout << "\t[null]" << endl; cout << endl; /******* cast between non-related class *******/ cout << "dynamic_cast to non-related class:" << endl; Stranger* stranger_d = dynamic_cast
(daughter_d); if (stranger_d) { stranger_d->Self_Introduce(); stranger_d->Speak(); } else cout <<"\t[null]"<
(son_s); //Error, invalid cast cout << "reinterpret_cast to non-related class:" << endl; Stranger* stranger_r = reinterpret_cast
(son_s); if (stranger_r) { stranger_d->Self_Introduce(); //stranger_d->Speak(); //This line would cause program crush, //as "name" could not be found corretly. } else cout << "\t[null]" << endl; cout << endl; /******* cast back*******/ cout << "use dynamic_cast to cast back from static_cast:" << endl; Children* child_s = dynamic_cast
(father_s); if (child_s) { child_s->Speak(); child_s->Work(); } else cout << "\t[null]" << endl; //cout<
<
(stranger_r); if (child_r) { child_r->Speak(); child_r->Work(); } else cout << "\t[null]" << endl; delete daughter_d; delete son_s; delete father_d; delete mother_s; return 0;}

输出结果:

/********************* Result *********************///dynamic_cast from child class to base class://	I am Daughter who pretend to be my mother, I love my parents.//	I am Daughter who pretend to be my mother, I need to work for my family.//static_cast from child class to base class://	I am Son who pretend to be my father, I love my parents.//	I am Son who pretend to be my father, I need to work for my family.////dynamic_cast from base class to child class://	[null]//static_cast from base class to child class://	I am Mother who pretend to be a my daugher, I love my children.//	I am Mother who pretend to be a my daugher, I need to study for future.////dynamic_cast to non-related class://	[null]//reinterpret_cast to non-related class://	I am a stranger////use dynamic_cast to cast back from static_cast://	I am Son who pretend to be my father, I love my parents.//	I am Son who pretend to be my father, I need to work for my family.//use dynamic_cast to cast back from reinterpret_cast://	[null]

 

从上边的代码和输出结果可以看出:

对于从子类到基类的指针转换,static_cast和dynamic_cast都是成功并且正确的(所谓成功是说转换没有编译错误或者运行异常;所谓正确是指方法的调用和数据的访问输出是期望的结果),这是面向对象多态性的完美体现。

从基类到子类的转换,static_cast和dynamic_cast都是成功的,但是正确性方面,我对两者的结果都先进行了是否非空的判别:dynamic_cast的结果显示是空指针,而static_cast则是非空指针。但很显然,static_cast的结果应该算是错误的,子类指针实际所指的是基类的对象,而基类对象并不具有子类的Study()方法(除非妈妈又想去接受个"继续教育")。

 

对于没有关系的两个类之间的转换,输出结果表明,dynamic_cast依然是返回一个空指针以表示转换是不成立的;static_cast直接在编译期就拒绝了这种转换。

reinterpret_cast成功进行了转换,而且返回的值并不是空指针,但是结果显然是错误的,因为Children类显然不具有Stranger的Self_Introduce()。虽然两者都具有name数据成员和Speak()方法,,Speak()方法也只是调用了该相同名称的成员而已,但是对于Speak()的调用直接造成了程序的崩溃。

 

其实前面static_cast的转换的结果也会跟reinterpret_cast一样造成的程序的崩溃,只是类的方法都只有一份,只有数据成员属于对象,所以在调用那些不会访问对象的数据的方法时(如Stranger的Self_Introduce())并不会造成崩溃。而daughter_s->Speak();和daughter_s->Study();调用了数据成员却没有出现运行错误,则是因为该成员是从基类继承下来的,通过地址偏移可以正确的到达数据成员所在的地址以读取出数据。

最后,程序里还用dynamic_cast希望把用其他转换运算符转换过去的指针转换回来。对于使用static_cast转换后指向了子类对象的基类指针,dynamic_cast判定转换是合理有效的,因此转换成功获得一个非空的指针并且正确输出了结果;而对于reinterpret_cast转换的类型,的确如它的功能一样——重新解析,变成新的类型,所以才得到dynamic_cast判定该类型已经不是原来的类型结果,转换得到了一个空指针。

总得说来,static_cast和reinterpret_cast运算符要么直接被编译器拒绝进行转换,要么就一定会得到相应的目标类型的值。 而dynamic_cast却会进行判别,确定源指针所指的内容,是否真的合适被目标指针接受。如果是否定的,那么dynamic_cast则会返回null。这是通过检查来判定的,它还受到编译器的影响,有些编译器需要设置开启才能让程序正确运行(导师的详细介绍了Visual Studio的情况),因此dynamic_cast也就不能用传统的转换方式来实现了。

 

虚函数(virtual function)对dynamic_cast的作用

已经在前面反复提到过,但是这个多态性到底要如何体现呢?dynamic_cast真的允许任意对象指针之间进行转换,只是最后返回个null值来告知转换无结果吗?

实际上,这一切都是在起作用。

在C++的面对对象思想中,虚函数起到了很关键的作用,当一个类中拥有至少一个虚函数,那么编译器就会构建出一个来指示这些函数的地址,假如继承该类的子类定义并实现了一个同名并具有同样的方法重写了基类中的方法,那么虚函数表会将该函数指向新的地址。此时多态性就体现出来了:当我们将基类的指针或引用指向子类的对象的时候,调用方法时,就会顺着虚函数表找到对应子类的方法而非基类的方法。

当然虚函数表的存在对于效率上会有一定的影响,首先构建虚函数表需要时间,根据虚函数表寻到到函数也需要时间。

因为这个原因如果没有继承的需要,一般不必在类中定义虚函数。但是对于继承来说,虚函数就变得很重要了,这不仅仅是实现多态性的一个重要标志,同时也是dynamic_cast转换能够进行的前提条件。

假如去掉上个例子中Stranger类析构函数前的virtual,那么语句

Children* child_r = dynamic_cast<Children*> (stranger_r);

在编译期就会直接报出错误,具体原因不是很清楚,我猜测可能是因为当类没有虚函数表的时候,dynamic_cast就不能用RTTI来确定类的具体类型,于是就直接不通过编译。

这不仅仅是没有继承关系的类之间的情况,如果基类或者子类没有任何虚函数(如果基类有虚函数表,子类当然是自动继承了该表),当他们作为dynamic_cast的源类型进行转换时,编译也会失败。

这种情况是有可能存在的,因为在设计的时候,我们可能不需要让子类重写任何基类的方法。但实际上,这是不合理的。导师在讲解多态性的时候,时刻强调了一点:如果要用继承,那么一定要让析构函数是虚函数;如果一个函数是虚函数,那么在子类中也要是虚函数。

我会将导师关于"为何继承中析构函数必须是虚函数"的讲解总结一下,当然你也可以看来了解原因。

 

你可能感兴趣的文章
使用Turbine聚合监控
查看>>
Zuul案例、常见使用方式
查看>>
SpringCloudConfig--ConfigServer从本地读取配置文件
查看>>
构建高可用的Config Server、使用Spring Cloud Bus刷新配置
查看>>
Nginx——重写与重定向
查看>>
Nginx——防盗链的配置
查看>>
TCP——粘包/拆包
查看>>
ChannelHandler和ChannelPipeline
查看>>
Netty——传输API
查看>>
Netty——ByteBuf的API
查看>>
Netty——ChannelHandler和ChannelPipeline
查看>>
Netty——ChannelHandlerContext
查看>>
Netty——EventLoop和线程模型
查看>>
Camera 图像处理原理分析- 色彩篇 二
查看>>
Camera 图像处理原理分析- 色彩篇 三
查看>>
Camera 图像处理原理分析- 亮度及曝光控制
查看>>
Camera 图像处理原理分析- 抗噪 变焦 频闪 等
查看>>
c语言核心技术 二
查看>>
udev文件系统的使用和基本工作原理分析
查看>>
快速理解Docker - 容器级虚拟化解决方案
查看>>