dynamic_cast报错 异常

2023-11-18

 转载请标明是引用于 http://blog.csdn.net/chenyujing1234

 代码:

http://www.rayfile.com/zh-cn/files/89459c23-7a0b-11e1-908f-0015c55db73d/

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<CheckBoxGroup *>(pChild))
	{
		printf("dynamic_cast of pChild is exist\n");
	}




 解决方法是:

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

 

参考下面文章:

http://www.cnblogs.com/ider/archive/2011/08/01/cpp_cast_operator_part5.html

 

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

static_cast一样,dynamic_cast的转换也需要目标类型和源对象有一定的关系:继承关系。 更准确的说,dynamic_cast是用来检查两者是否有继承关系。因此该运算符实际上只接受基于类对象的指针和引用的类转换。从这个方面来看,似乎dynamic_cast又和reinterpret_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 <string>
#include <iostream>
#include <Windows.h>
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<Parents*> (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<Parents*> (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<Children*> (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<Children*> (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<Stranger*> (daughter_d);
	if (stranger_d)
	{
		stranger_d->Self_Introduce();
		stranger_d->Speak();	
	}
	else cout <<"\t[null]"<<endl;
	
	//Stranger* stranger_s = static_cast<Stranger*> (son_s);    //Error, invalid cast
	
	cout << "reinterpret_cast to non-related class:" << endl;
	Stranger* stranger_r = reinterpret_cast<Stranger*> (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<Children*> (father_s);
	if (child_s)
	{
		child_s->Speak();
		child_s->Work();
	}
	else cout << "\t[null]" << endl;
	
    //cout<<typeid(stranger_r).name()<<endl;
    
	cout << "use dynamic_cast to cast back from reinterpret_cast:" << endl;
	Children* child_r = dynamic_cast<Children*> (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。这是通过检查"运行期类型信息"(Runtime type information,RTTI)来判定的,它还受到编译器的影响,有些编译器需要设置开启才能让程序正确运行(导师的PPT详细介绍了Visual Studio的情况),因此dynamic_cast也就不能用传统的转换方式来实现了。

 

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

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

实际上,这一切都是虚函数(virtual function)在起作用。

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

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

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

假如去掉上个例子中Stranger类析构函数前的virtual,那么语句
Children* child_r = dynamic_cast<Children*> (stranger_r);

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

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

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

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

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

dynamic_cast报错 异常 的相关文章

随机推荐

  • 无法启动此程序因为计算机中丢失api-ms-win-crt-runtime-l1-1-0.dll

    系列文章目录 文章目录 系列文章目录 前言 安装 前言 出现这个问题是因为本地api ms win crt runtime l1 1 0 dll 版本过低或者不存在 Visual C Redistributable for Visual S
  • 【铨顺宏项目推荐】RFID无线射频识别技术的设计思路

    一 项目背景 在传统的珠宝物流管理中 条形码技术通常被使用 虽然该技术可以在一定程度上提高物流管理效率 但仍不能满足现代珠宝行业的需求 条形码存储信息量低 信息不可追加 易损坏 读取位置要求高等问题逐渐显现 RFID与传统的条码识别方法相比
  • _thiscall调用约定的简单概念

    thiscall 我们知道在c中由三种调用约定 cdecl stdcall和 fastcall 其中 stdcall调用约定是windows平台的 在c 中还有一种约定 thiscall调用约定 它是一种类成员方法调用约定 当我们说起 th
  • python3神经网络学习NN学习初步(一)

    1 神经网络的概念 我们用一张图来了解一下吧 多层向前神经网络由以下部分组成 输入层 input layer 隐藏层 hidden layers 输入层 output layers 补充 一般第一层是输入层 最后一层是输出层 其他的的都是中
  • Impala presto hbase hive sparksql

    Impala 技术点梳理 http www cnblogs com TiestoRay p 10243365 html Impala 优点 实时性查询 计算的中间结果不写入磁盘 缺点 对于内存的依赖过于严重 内存溢出直接导致技术任务的失败
  • MainWindow.h

    ifndef MAINWINDOW H define MAINWINDOW H include
  • 中小企业如何低成本实施MES管理系统

    中小企业在市场竞争中需要有高效的管理体系来支持其运营和发展 中小企业MES管理系统是一种先进的管理系统 可以提升工厂智能化水平 提高生产效率 是中小企业必须采取的有效管理工具 然而 由于资金和技术的限制 中小企业往往难以承担高额的软件购置和
  • yocto编译常见问题及解决方法

    1 opt yocto rel share downloads exists but you do not appear to have write access to it 这个是没有权限往指定的目录里写 解决方法 将build目录下对应
  • oralce 超出表空间限额问题

    oralce 超出表空间限额问题 Pl sql建表时报 超出表空间限额 的错误 检查表空间 只占了3 的空间 最后经提醒原来是数据库用户默认只有15M的空间 最后通过修改用户的权限 不限制存储空间 解决问题 来自 ITPUB博客 链接 ht
  • 【VSCode】推荐一款Microsoft Visual Studio Code能在编辑器内智能补全代码的插件 - Tabnine AI

    Tabnine AI Autocomplete for Javascript Python Typescript PHP Go Java Ruby more Tabnine是一个AI代码补全插件 支持JavaScript Python Ja
  • openGL之API学习(一九四)glGenTextures glActiveTexture

    glGenTextures产生的是一个比较小的整数id 纹理单元名 glActiveTexture激活的是纹理单元号 GL TEXTUREi 它们二者的关系为GL TEXTUREi GL TEXTURE0 id glBindTexture使
  • MySQL server has gone away (BrokenPipeError(32, 'Broken pipe'))[MySQL插入内容超过4M]

    MySQL server has gone away BrokenPipeError 32 Broken pipe MySQL插入内容超过4M Bug描述 用Python的pymysql向MySQL数据库insert插入数据时 遇到报错信息
  • 估算服务器处理数据性能,服务器性能计算方法-20210720074826.docx-原创力文档

    一 数据库服务器性能计算需求分析 考虑到广州市公安局超级情报系统 SIS 设备升级项目的数据库 服务器的性能 我们建议采用主流的TPC C值进行性能估算 TPC C 是一种旨在衡量联机事务处理 OLTP 系统性能与可 伸缩 性的行业标准基准
  • Multi-mode pattern generator

    Multi mode pattern generator verilog编写 支持如下模式 Full screen White Full screen Black Full screen Red Full screen Green Full
  • JAVA操作Excel时文字自适应单元格的宽度设置方法

    使用JAVA操作Excel通常都使用JXL 方法很简单网上也有很多的教程 然后往往一些细节性的问题却导致我们这些Programmer苦恼不已 这两天帮一个朋友做一个Excel表格自动生成的小软件 就遇到的类似的问题 问题描述 通过Java向
  • 不同数据库的validationQuery检查语句

    数据库 validationQuery Oracle select 1 from dual MySQL select 1 Microsoft SQL Server select 1 DB2 select 1 from sysibm sysd
  • LeetCode83: 删除排序链表中的重复元素

    给定一个已排序的链表的头 head 删除所有重复的元素 使每个元素只出现一次 返回 已排序的链表 示例 1 输入 head 1 1 2 输出 1 2 示例 2 输入 head 1 1 2 3 3 输出 1 2 3 提示 链表中节点数目在范围
  • ASP高级计划与排产简介

    ASP Advanced Planning and Scheduling 高级计划与排产是一种计算机化的制造计划和排程系统 旨在帮助制造商更有效地管理其生产过程 它可以通过对订单需求 库存水平 生产能力和物料供应等关键信息的实时跟踪和分析
  • Git Bash ssh远程连接kali linux

    操作步骤 查看本机IP地址等网络相关信息 ifconfig 开启ssh服务 该命令正常情况下没有回显 service ssh start 查看ssh服务是否正常开启 如果正常开启 则此时有 active running 的提示 servic
  • dynamic_cast报错 异常

    转载请标明是引用于 http blog csdn net chenyujing1234 代码 http www rayfile com zh cn files 89459c23 7a0b 11e1 908f 0015c55db73d UnH