1. 程式人生 > >C++ 高階篇(四)—— 型別轉換高階

C++ 高階篇(四)—— 型別轉換高階

目前為止,我們一直使用傳統的型別轉換符來進行簡單物件的型別轉換。例如,要把一個double型別的浮點型數字轉換為int 的整型數字,我們是這樣做的:

int i;
double d;
i = (int) d;

或者

i = int (d);

這樣做對基本資料型別時沒問題的,因為基本資料型別的轉換已經有標準的定義。同樣的操作也可以被在類或類的指標上,因此以下例子中的寫法也是沒有問題的:

    // class type-casting
    #include <iostream.h>
    
    class CDummy {
        int i;
    };
    
    class CAddition {
        int x,y;
      public:
        CAddition (int a, int b) { x=a; y=b; }
        int result() { return x+y;}
    };
    
    int main () {
        CDummy d;
        CAddition * padd;
        padd = (CAddition*) &d;
        cout << padd->result();
        return 0;
    }
		

雖然以上程式在C++中是沒有語法錯誤的(多數編譯器甚至不會產生警告資訊),但這段程式沒有什麼實際的邏輯意義。我們使用了CAddition 的成員函式result 而沒有定義一個相應的該類的物件:padd 並不是一個物件,它只是一個指標,被我們賦值指向一個毫無關係的物件的地址。當在程式執行到訪問它的result 成員函式時,將會有一個執行錯誤(run-time error)產生,或生成一個意外的結果。

為了控制這種類之間的轉換,ANSI-C++ 標準定義了4種新的型別轉換操作符: reinterpret_cast, static_cast, dynamic_cast 和 const_cast。所有這些操作符都是同樣的使用格式:

reinterpret_cast <new_type> (expression)
dynamic_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)

這裡new_type 是要轉換成的目標型別,expression 是要被轉換的內容。為了便於理解,模仿傳統轉換操作符,它們的含義是這樣的:

(new_type) expression
new_type (expression) 

reinterpret_cast

reinterpret_cast 可以將一個指標轉換為任意其它型別的指標。它也可以用來將一個指標轉換為一個整型,或反之亦然。

這個操作符可以在互不相關的類之間進行指標轉換,操作的結果是簡單的將一個指標的二進位制資料(binary copy)複製到另一個指標。對指標指向的內容不做任何檢查或轉換。

如果這種複製發生在一個指標到一個整數之間,則對其內容的解釋取決於不同的系統,因此任何實現都是不可移植(non portable)的。一個指標如果被轉換為一個能夠完全儲存它的足夠大的整數中,則是可以再被轉換回來成為指標的。

例如:

class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast<B*>(a);

reinterpret_cast 對所有指標的處理與傳統的型別轉換符所作的一模一樣。


static_cast

static_cast 可以執行所有能夠隱含執行的型別轉換,以及它們的反向操作(即使這種方向操作是不允許隱含執行的)。

用於類的指標,也就是說,它允許將一個引申類的指標轉換為其基類型別(這是可以被隱含執行的有效轉換),同時也允許進行相反的轉換:將一個基類轉換為一個引申類型別。

在後面一種情況中,不會檢查被轉換的基類是否真正完全是目標型別的。例如下面的程式碼是合法的:

class Base {};
class Derived: public Base {};
Base * a = new Base;
Derived * b = static_cast(a);

static_cast除了能夠對類指標進行操作,還可以被用來進行類中明確定義的轉換,以及對基本型別的標準轉換:

double d=3.14159265;
int i = static_cast<int>(d);

譯者注:如果你對這部分看不太懂,請結合下面的dynamic_cast一起看,也許會幫助理解。


dynamic_cast

dynamic_cast 完全被用來進行指標的操作。它可以用來進行任何可以隱含進行的轉換操作以及它們被用於多型類情況下的方向操作。然而與static_cast不同的是, dynamic_cast 會檢查後一種情況的操作是否合法,也就是說它會檢查型別轉換操作是否會返回一個被要求型別的有效的完整的物件。

這種檢查是在程式執行過程中進行的。如果被轉換的指標所指向的物件不是一個被要求型別的有效完整的物件,返回值將會是一個空指標NULL 。

   class Base { virtual dummy(){}; };
   class Derived : public Base { };
   

   Base* b1 = new Derived;
   Base* b2 = new Base;
   Derived* d1 = dynamic_cast(b1);   // succeeds
   Derived* d2 = dynamic_cast(b2);   // fails: returns NULL
   

如果型別轉換被用在引用(reference)型別上,而這個轉換不可能進行的話,一個bad_cast 型別的例外(exception)將會被丟擲:

  class Base { virtual dummy(){}; };
  class Derived : public Base { };
  
  Base* b1 = new Derived;
  Base* b2 = new Base;
  Derived d1 = dynamic_cast(b1);   // succeeds
  Derived d2 = dynamic_cast(b2);   // fails: exception thrown
  

const_cast

這種型別轉換對常量const 進行設定或取消操作:

class C {};
const C * a = new C;
C * b = const_cast<C*> (a);

其他3種cast 操作符都不可以修改一個物件的常量屬性(constness)。


typeid

ANSI-C++ 還定義了一個新的操作符叫做 typeid ,它檢查一個表示式的型別:

typeid (expression)

這個操作符返回一個型別為type_info的常量物件指標,這種型別定義在標準頭函式中。這種返回值可以用操作符 == 和 != 來互相進行比較,也可以用來通過name()函式獲得一個描述資料型別或類名稱的字串,例如:

    // typeid, typeinfo
    #include <iostream.h>
    #include <typeinfo>
    
    class CDummy { };
    
    int main () {
        CDummy* a,b;
        if (typeid(a) != typeid(b)) {
            cout << "a and b are of different types:\n";
            cout << "a is: " << typeid(a).name() << '\n';
            cout << "b is: " << typeid(b).name() << '\n';
        }
        return 0;
    }
			
a and b are of different types:
a is: class CDummy *
b is: class CDummy

相關推薦

C++ 高階—— 型別轉換高階

目前為止,我們一直使用傳統的型別轉換符來進行簡單物件的型別轉換。例如,要把一個double型別的浮點型數字轉換為int 的整型數字,我們是這樣做的: int i; double d; i = (int) d; 或者 i = int (d); 這樣做對基本資料型別時沒問題的,

spring 官方文件的介面理解整理型別轉換spring例項解析

上篇文章解析了spring型別轉換的介面和他們的分工,怎麼通過設計模式實現轉換功能。 這篇需要些上篇的知識,如果沒有看可以從這兒跳轉spring 官方文件的介面理解整理(三)型別轉換 一、準備新建Maven專案,pom.xml內容如下 <properties>

Java高階——反射

  之前寫到了設計模式的代理模式,因為下一篇動態代理等內容需要用到反射的知識,所以在之前Java篇的基礎上再寫一篇有關反射的內容,還是以實際的程式為主,瞭解反射是做什麼的、應該怎麼用。 一、什麼是反射   反射就是把Java類中的各個成分對映成一個個的Java物件。即在執行狀態中,對於任意一個類,都能夠知道這

C#高階6

1.程序和執行緒 一般情況下,一個應用程式下有一個程序,有好幾個執行緒 在一個程序中有多個執行緒,這些執行緒共享程序的記憶體空間。 在程序中通過互斥鎖,防止多個執行緒同一時間讀寫某一塊記憶體區域。 使用訊號量保證多個執行緒不會相互衝突 通過委託開啟一個執行緒,一般一個比較耗時的操作,

C#高階5

1.反射和特性 有關程式以及型別的資料被稱為元資料,特們儲存在程式的程式集中。 程式在執行時,可以檢視其他程式及或其本身的元資料。一個執行的程式檢視本身元資料或者其他程式集的元資料的行為叫做反射。 Type類是抽象類,用來包含型別的特性。 GetFields獲取類中的相關屬性(公有的

C#高階4

1.LINQ語句 建立一個類,在這個類中重寫了ToString方法,在直接列印類的時候列印類中的屬性 class Master { public int Id { get; set; } public string Name { get; set; }

C語言陣列二維陣列

  二維陣列宣告: int a[2][3] ={{1,2,3},{4,5,6}; //兩行 三列 1 2 3 4 5 6           二

C語言函式函式的設計

1. 函式設計的時候,如果使用到全域性變數,就儘量通過引數的形式傳遞進來     也就是說,保持 函式 跟 外部的互動 只有 引數 和 返回值   2. 在有引數的情況下,或者有數值輸入的時候,要先進行錯誤判斷. int func( int *buf){   //1.錯誤判斷 i

C++ 重點知識梳理 -------- 型別轉換、指標

dynamic_cast:該轉換符用於將一個指向派生類的基類指標或引用轉換為派生類的指標或引用。 const_cast:最常用的用途就是刪除const屬性。 static_cast:static_cast本質上是傳統c語言強制轉換的替代品,比C型別轉換更嚴格, 該操作符用於非多型型別的轉換,任何標準轉換都

Kotlin 其他 --- 型別的檢查與轉換“is”與“as”

1、is 與 !is 操作符 我們可以在執行時通過使用 is 操作符或其否定形式 !is 來檢查物件是否符合給定型別: if (obj is String) { print(obj.length) } if (obj !is String) {

Linq之Expression高階常用表示式型別

目錄 寫在前面 系列文章 變量表達式 常量表達式 條件表示式 賦值表示式 迴圈表示式 塊表示式 總結 寫在前面 首先回顧一下上篇文章的內容,上篇文章介紹了表示式樹的解析和編譯。如果忘記了,可以通過下面系列文章提供的入口進行復習。這篇文章將介紹常見的表示式型別。 常見的表示式型別都有個共同的基類Expre

C語言面試題---指標

解析:首先看最後一個問題, c  是第一個元素的地址, *c  是第一行元素的首地址,其實第一行元素的地址就是第一個元素的地址, **c  是提取第一個元素。為什麼 c  , *c  的值相等?c是陣列名,是一個二維指標,它的值就是陣列的首地址,也即第一行元素的首地址(等於 *c  ),也等於第一行第一個元素

C++ 高階—— 預處理指令

預處理指令是我們寫在程式程式碼中的給前處理器(preprocessor)的 命令,而不是程式本身的語句。前處理器在我們編譯一個C++程式時由編譯器自動執行,它負責控制對程式程式碼的第一次驗證和消化。 所有這些指令必須寫在單獨的一行中,它們不需要加結尾的分號;。 #defi

C++高階2——運算子過載及流類庫

引言:                C++倆大難點,一個是指標,一個就是運算子過載及流類庫,你瞭解嗎? 概述:               運算子過載就是對已有的運算子重新進行定義,賦予其另一種功能

linux操作系統基礎

空閑 僵屍進程 標準 為什麽 嘗試 mount命令 性能分析 包含 put 系統監控 1. 系統監視和進程控制工具—top和free1) 掌握top命令的功能:top命令是Linux下常用的性能分析工具,能夠實時顯示系統中各個進程的資源占用狀況,類似於Windows的

回顧2017系列:永不過時的設計資源

如果你是一個留心者,你會發現近幾年的設計潮流和趨勢隨著科技的革新在不斷的更替和進步。網絡上的設計資源,教學視頻也愈加的豐富和多樣,為眾多設計行業的後來者提供了巨大的便利。設計們也樂於分享自己的設計經驗和技巧為初入行的菜鳥們提供幫助和指導。今天的設計行業也不再那麽神秘。 2017年是設計行業發

C# Stream -- BufferedStream

擴展 support turn har reat rst fault false span BufferedStream 目錄: 簡單介紹一下BufferedStream 如何理解緩沖區? BufferedStream的優勢 從BufferedStream 中學習裝飾模式

C# Stream -- TextReader 和StreamReader

ros 開頭 設置 block 哪些 {0} 實例 adt 一點 TextReader 和StreamReader 目錄: 為什麽要介紹 TextReader? TextReader的常用屬性和方法 TextReader 示例 從StreamReader想到多態 簡單介紹下

面向對象

() str 構造函數 function pro 兩個 proto creat ron function CreatePerson(name){ this.name = name; this.showName = function(){ ale

Python入門之字符串、字典、集合

Python 字典 1、字符串操作 字符串是無法修改的,只能作為查詢.在python中,加了引號的字符就是字符串類型,python並沒有字符類型。定義:name=‘kim‘ #name=str(‘kim‘) 用於標識:描述性的內容,如姓名,性別,國籍,種族那單引號、雙引號、多引號有什麽區別呢? 讓我