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.pswp.cn/news/384372.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384372.shtml
英文地址,請注明出處:http://en.pswp.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;數組變為 […