C++ dynamic_cast操作符

转载:http://www.weixueyuan.net/view/6377.html

在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。Dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。

例1:

  1. #include<iostream>
  2. using namespace std;
  3. class base
  4. {
  5. public :
  6. void m(){cout<<"m"<<endl;}
  7. };
  8. class derived : public base
  9. {
  10. public:
  11. void f(){cout<<"f"<<endl;}
  12. };
  13. int main()
  14. {
  15. derived * p;
  16. p = new base;
  17. p = static_cast<derived *>(new base);
  18. p->m();
  19. p->f();
  20. return 0;
  21. }
本例中定义了两个类:base类和derived类,这两个类构成继承关系。在base类中定义了m函数,derived类中定义了f函数。在前面介绍多态时,我们一直是用基类指针指向派生类或基类对象,而本例则不同了。本例主函数中定义的是一个派生类指针,当我们将其指向一个基类对象时,这是错误的,会导致编译错误。但是通过强制类型转换我们可以将派生类指针指向一个基类对象,p = static_cast<derived *>(new base);语句实现的就是这样一个功能,这样的一种强制类型转换时合乎C++语法规定的,但是是非常不明智的,它会带来一定的危险。在程序中p是一个派生类对象,我们将其强制指向一个基类对象,首先通过p指针调用m函数,因为基类中包含有m函数,这一句没有问题,之后通过p指针调用f函数。一般来讲,因为p指针是一个派生类类型的指针,而派生类中拥有f函数,因此p->f();这一语句不会有问题,但是本例中p指针指向的确实基类的对象,而基类中并没有声明f函数,虽然p->f();这一语句虽然仍没有语法错误,但是它却产生了一个运行时的错误。换言之,p指针是派生类指针,这表明程序设计人员可以通过p指针调用派生类的成员函数f,但是在实际的程序设计过程中却误将p指针指向了一个基类对象,这就导致了一个运行期错误。

产生这种运行期的错误原因在于static_cast强制类型转换时并不具有保证类型安全的功能,而C++提供的dynamic_cast却能解决这一问题,dynamic_cast可以在程序运行时检测类型转换是否类型安全。当然dynamic_cast使用起来也是有条件的,它要求所转换的操作数必须包含多态类类型(即至少包含一个虚函数的类)。

例2:
  1. #include<iostream>
  2. using namespace std;
  3. class base
  4. {
  5. public :
  6. void m(){cout<<"m"<<endl;}
  7. };
  8. class derived : public base
  9. {
  10. public:
  11. void f(){cout<<"f"<<endl;}
  12. };
  13. int main()
  14. {
  15. derived * p;
  16. p = new base;
  17. p = dynamic_cast<derived *>(new base);
  18. p->m();
  19. p->f();
  20. return 0;
  21. }
在本例中利用dynamic_cast进行强制类型转换,但是因为base类中并不存在虚函数,因此p = dynamic_cast<derived *>(new base);这一句会编译错误。dynamic_cast能否正确转换与目标类型是否为多态类类型无关,dynamic_cast要求被转换的类型必须为多态类类型。为了解决本例中的语法错误,我们可以将base类中的函数m声明为虚函数,virtual void m(){cout<<"m"<<endl;}。

dynamic_cast还要求<>内部所描述的目标类型必须为指针或引用。如例3所示,如果我们将例2中的主函数换成例3的形式,这也是无法通过编译的。

例3:
  1. int main()
  2. {
  3. base b;
  4. dynamic_cast<derived>(b);
  5. return 0;
  6. }
我们来看一下正确使用dynamic_cast的代码。

例4:
#include<iostream>
using namespace std;class base
{
public :virtual void m(){cout<<"m"<<endl;}
};class derived : public base
{
public:void f(){cout<<"f"<<endl;}
};int main()
{derived * p;p = dynamic_cast<derived *>(new base);if(p){p->m();p->f();       }elsecout<<"Convert not safe!"<<endl;return 0;
}
在本例中通过dynamic_cast来初始化指针p,在初始化过程中dynamic_cast会检测操作数new base转换为目标类型derived *是否能保证类型安全,如果类型安全则将new base结果赋给p指针,否则返回0,也即false。而本例中是要用基类对象地址去初始化派生类指针,这显然是无法保证类型安全的,因此p最后得到的返回值是0。在主函数中经过判断语句,最终程序输出“Convert not safe!”。

Dynamic_cast转换有自己的规则,下面将通过示例来介绍转换规则。

例4:
  1. #include<iostream>
  2. using namespace std;
  3. class base
  4. {
  5. public :
  6. virtual void m(){cout<<"m"<<endl;}
  7. };
  8. class derived : public base
  9. {
  10. public:
  11. virtual void f(){cout<<"f"<<endl;}
  12. };
  13. int main()
  14. {
  15. derived * d;
  16. d = dynamic_cast<derived *>(new base);
  17. if(d)
  18. {
  19. cout<<"Base to Derived is ok"<<endl;
  20. delete d;
  21. }
  22. else
  23. cout<<"Base to Derived is error"<<endl;
  24. base * b;
  25. b = dynamic_cast<base *>(new derived);
  26. if(b)
  27. {
  28. cout<<"Derived to Base is ok"<<endl;
  29. delete b;
  30. }
  31. else
  32. cout<<"Derived to Base is error"<<endl;
  33. return 0;
  34. }
本例分别定义了两个类:base类和derived类,这两个类构成继承关系,为了测试dynamic_cast转换规则,我们在类中各自定义了一个虚函数。在本例的主函数中我们分别测试基类转换为派生类和派生类转换为基类时dynamic_cast转换返回值。本例最终运行结果如下:
    Base to Derived is error
    Derived to Base is ok

从结果可以看出从不能将指向基类对象的指针转换为指向派生类对象的指针,但是可以将指向派生类对象的指针转换为指向基类对象的指针。

例5:
  1. #include<iostream>
  2. using namespace std;
  3. class A
  4. {
  5. public :
  6. virtual void m(){cout<<"m"<<endl;}
  7. };
  8. class B
  9. {
  10. public:
  11. virtual void f(){cout<<"f"<<endl;}
  12. };
  13. int main()
  14. {
  15. A * a;
  16. a = dynamic_cast<A *>(new B);
  17. if(a)
  18. {
  19. cout<<"B to A is ok"<<endl;
  20. delete a;
  21. }
  22. else
  23. cout<<"B to A is error"<<endl;
  24. B * b;
  25. b = dynamic_cast<B *>(new A);
  26. if(b)
  27. {
  28. cout<<"A to B is ok"<<endl;
  29. delete b;
  30. }
  31. else
  32. cout<<"A to B is error"<<endl;
  33. return 0;
  34. }
在本例中,定义了两个类A和B,这两个类不构成继承关系,我们尝试将指向两个类对象的指针进行互相转换,看程序运行结果:
    B to A is error
    A to B is error

从程序运行结果不难看出,任意两个不相关的多态类类型之间的转换也是不能进行的。

总结一下dynamic_cast转换规则,只允许指向派生类对象的指针转换为指向基类对象的指针。

C++提供的两个类型转换操作符static_cast和dynamic_cast,static_cast可以用于任何类型的强制类型转换,但是它不保证转换过程中的类型安全,dynamic_cast只能用于多态类类型的转换,而且要求转换的目的类型必须为指针或引用,并且它可以保证转换过程中类型安全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构(五)树

数据结构&#xff08;五&#xff09;树一、基本操作树是n个节点的有限集&#xff0c;它是一种递归的数据结构 一、基本操作 #include <stdio.h> #include <stdlib.h> #include <iostream>#define Elemtype charusing namespace std; typedef struct BiTNod…

C++ typeid操作符

转载&#xff1a;http://www.weixueyuan.net/view/6378.html typeid操作符用于判断表达式的类型&#xff0c;注意它和sizeof一样是一个操作符而不是函数。如果需要使用typeid操作符&#xff0c;最好加上typeinfo头文件。 给出以下定义 int a;double b;char * c;long d; 下表列…

数据结构(五)层次遍历

数据结构&#xff08;五&#xff09;层次遍历// linear_listqueue.cpp : This file contains the main function. Program execution begins and ends there. //#include <iostream> #include <stdlib.h> #include <stdio.h> #define ElemType BiTree using …

C++成员函数指针的应用

转载&#xff1a;http://www.cppblog.com/colys/archive/2009/08/18/25785.html C中&#xff0c;成员指针是最为复杂的语法结构。但在事件驱动和多线程应用中被广泛用于调用回叫函数。在多线程应用中&#xff0c;每个线程都通过指向成员函数的指针来调用该函数。在这样的应用中…

cv2.VideoCapture()无法打开视频解决方法

cv2.VideoCapture无法打开视频解决方法问题解决方法问题 cv2.VideoCapture打开mp4文件&#xff0c;直接报错 解决方法 我们打开D:\opencv_3.4.2_Qt\opencv_3.4.2_Qt\x86\bin\&#xff08;opencv的dll动态库中找到&#xff09; 找到opencv_ffmpeg342.dll文件&#xff0c;放入…

函数指针指向类的静态成员函数

转载&#xff1a;http://www.cnblogs.com/dongyanxia1000/p/4906592.html 1. 代码 1 #include<iostream>2 #include<stdio.h>3 using namespace std;4 class Point5 {6 public:7 Point(int x0,int y0):x(x),y(y)8 { 9 count; 10 } 11 P…

Qt+OpenCV打开视频文件并在窗口界面上显示

QtOpenCV打开视频文件并在窗口界面上显示1、新建一个Qt Widgets Application&#xff0c;工程配置文件&#xff08;.pro文件&#xff09;内容如下&#xff1a;#------------------------------------------------- # # Project created by QtCreator 2021-03-19T09:06:07 # #--…

OpenCV Mat的数据类型

OpenCV Mat的数据类型Mattype类型内存拷贝简单实现Mat Mat类(Matrix的缩写)是OpenCV用于处理图像而引入的-一个封装类。他是一个自动内存管理工具。 Mat:本质上是由两个数据部分组成的类:(包含信息有矩阵的大小&#xff0c;用于存储的方法&#xff0c;矩阵存储的地址等)矩阵头…

C++指向成员函数的指针

转载&#xff1a;http://www.cnblogs.com/tracylee/archive/2012/11/15/2772176.html C指向函数的指针定义方式为&#xff1a; 返回类型 &#xff08;*指针名&#xff09;&#xff08;函数参数列表&#xff09;&#xff0c;例如 void &#xff08;*p&#xff09;&#xff08;in…

OpenCV基础知识 图像

OpenCV基础知识 图像位图模式灰度模式RGB模式位图模式 位图模式是是1位深度的图像&#xff0c;只有黑和白两种颜色。它可以由扫描或置入黑色的矢量线条图像生成&#xff0c;也能由灰度模式转换而成。其他图像模式不能直接转换为位图模式。 灰度模式 灰度模式是8位的图像&…

C++中引用与指针的区别(详细介绍)

转载&#xff1a;http://www.cnblogs.com/tracylee/archive/2012/12/04/2801519.html C&#xff0b;&#xff0b;中的引用与指针的区别指向不同类型的指针的区别在于指针类型可以知道编译器解释某个特定地址&#xff08;指针指向的地址&#xff09;中的内存内容及大小&#xff…

mysql远程连接权限grant all privileges on *.* to ‘root‘@‘%‘ identified by ‘123456‘ with grant option语句报错

mysql远程连接权限grant all privileges on *.* to ‘root‘‘%‘ identified by ‘123456‘ with grant option语句报错记录一下自己安装mysql遇到的小坑grant all privileges on *.* to ‘root‘‘%‘ identified by ‘123456‘ with grant option只适用于mysql8.0之前的版本…

C++虚继承的概念

转载&#xff1a;http://blog.csdn.net/crystal_avast/article/details/7678704 C中虚拟继承的概念 为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题&#xff0c;将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只…

数组名和取数组名的区别

先来个简单的小案例 #include <stdio.h> #include <iostream>using namespace std;int main() {int a[10] { 0 };printf("%d\n", a);printf("%d\n", &a);printf("%d\n", a1);printf("%d\n", &a1);printf("…

C++继承详解三 ----菱形继承、虚继承

转载&#xff1a;http://blog.csdn.net/pg_dog/article/details/70175488 今天呢&#xff0c;我们来讲讲菱形继承与虚继承。这两者的讲解是分不开的&#xff0c;要想深入了解菱形继承&#xff0c;你是绕不开虚继承这一点的。它俩有着什么关系呢&#xff1f;值得我们来剖析。 菱…

Linux :IO多路复用模型

转载&#xff1a;http://blog.csdn.net/mr253727942/article/details/50827127 一、IO多路复用定义 IO多路复用允许应用在多个文件描述符上阻塞&#xff0c;并在某一个可以读写时通知&#xff0c; 一般遵循下面的设计原则&#xff1a;、 IO多路复用&#xff1a;任何文件描述符…

leetcode(一)刷题两数之和

给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 示例 1&#xff1a; 输入&#xff1a;nums [2,7,11,15], target 9 输出&#xff1a;[0,1] 解释&#xff1a;因为 nums[…

Linux并发服务器编程之多线程并发服务器

转载&#xff1a;http://blog.csdn.net/qq_29227939/article/details/53782198 上一篇文章使用fork函数实现了多进程并发服务器&#xff0c;但是也提到了一些问题&#xff1a; fork是昂贵的。fork时需要复制父进程的所有资源&#xff0c;包括内存映象、描述字等&#xff1b;目…

leetcode(二)二分法查找算法

给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 解释: 9 出现在…

leetcode(977)有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,10] 输出&#xff1a;[0,1,9,16,100] 解释&#xff1a;平方后&#xff0c;数组变为 […