Explicit 關鍵字和各類類型轉換(轉)

說實話,歷來沒有感受到這個關鍵字有用,直到今天。java

explicit的意思是明顯的,和它相對應的一個詞是implicit意思是隱藏的。linux

我參考了MSDN和《c++標準程序庫》對這個關鍵字的描述,並參考了網絡上對這個關鍵字的解釋。現將它的使用方法和總結記錄以下:ios

首先這個關鍵字只能用在類構造函數。它的做用是不能進行隱式轉換c++

class gxgExplicit  //沒有關鍵字explicit的類程序員

{express

public:windows

   int _size;安全

   gxgExplicit(int size)網絡

   {函數

      _size = size;

   }

};

下面是調用

   gxgExplicit gE1(24);     //這樣是沒有問題的

   gxgExplicit gE2 = 1;     //這樣也是沒有問題的

   gxgExplicit gE3;         //這樣是不行的,沒有默認構造函數

   gE1 = 2;                 //這樣也是沒有問題的

   gE2 = 3;                 //這樣也是沒有問題的

   gE2 = gE1;               //這樣也是沒有問題的

 

可是假如gxgExplicit修改成Stack,咱們的_size表明的是堆棧的大小,那麼調用的第二句就顯得不三不四,並且容易讓人疑惑。這並非可讓代碼閱讀者明白和接受的形式,雖然它是合法的(編譯器能夠經過編譯)。這是由於編譯器默認狀況下有隱式轉換的功能,你輸入gE2 = 1就編譯成同第一句相同的結果。因此,explicit就派上了用場。修改代碼爲:

class gxgExplicit

{

public:

   int _size;

   explicit gxgExplicit(int size)

   {

      _size = size;

   }

};

繼續上面的調用:

   gxgExplicit gE1(24);     //這樣是沒有問題的

   gxgExplicit gE2 = 1;     //這樣是不行的,關鍵字取消了隱式轉換

   gxgExplicit gE3;         //這樣是不行的,沒有默認構造函數

   gE1 = 2;                 //這樣是不行的,關鍵字取消了隱式轉換

   gE2 = 3;                 //這樣是不行的,關鍵字取消了隱式轉換

   gE2 = gE1;               //這樣是不行的,關鍵字取消了隱式轉換,除非類實現操做符「=」的重載。

這是編譯器(vs2005)顯示:cannot convert from 'int' to 'gxgExplicit'

從這裏也就看出這個關鍵字的做用是將編譯器隱式轉換的功能給屏蔽掉

 

MSDN上有一個注意點描述了下面的事實,當構造函數參數超過兩個時自動取消隱式轉換。例如

class gxgExplicit

{

private:

   int _size;

   int _age;

public:

   explicit gxgExplicit(int age, int size)

   {

      _age = age;

      _size = size;

   }

};

這是有沒有關鍵字效果是同樣的。那就是至關於有這個關鍵字

可是另一種狀況例外:其中只有一個必須輸入的參數,其他的爲有默認值的參數。

class gxgExplicit

{

private:

   int _size;

   int _age;

public:

   explicit gxgExplicit(int age, int size = 0)

   {

      _age = age;

      _size = size;

   }

};

class gxgExplicit

{

private:

   int _size;

   int _age;

int _hight;

public:

   explicit gxgExplicit(int age, int size = 0)

   {

      _age = age;

      _size = size;

      _hight = hight;

   }

};

 

這樣的狀況下至關於一個參數的效果。

到如今爲止。這個關鍵字就是這麼用了。

 

 

呵呵,今天來好好看看着幾個轉換操做符的用法。之前總是看着眼熟,可是用着手生。今天決定搞定這些個東西。

在C語言中類型轉換有幾種方式:

1.      (expression). 在表達式外邊加括號,由編譯器來決定怎麼改變。

2.      new_type(expression). 強制類型括號住表達式。

3.      (new_type)expression. 括號住強制類型。

4.      C語言容許的內置轉換。

這些轉換很是高效,我很是喜歡使用。特別是在指針轉換和數值轉換時用到的很是多。只要編寫程序的人知道本身要作什麼轉換,並知道應該怎樣轉換的話,我認爲上邊的轉換方式很是之好。可是沒有清楚的瞭解每一個轉換的細節的話,就有可能出現問題,好比指針指向不該該指向的區域:出現野指針或者指向位置錯誤(主要是對內存結構不瞭解),或者計算數值被截去等問題發生。

C++程序兼容C語言的轉化,可是針對面嚮對象語言的特性,設計瞭如下幾個類型轉換操做符。他們的出現是爲了C語言類型轉換中語義模糊和固有的危險陷阱,由於C語言不去判斷所要操做的類型轉換是否合理。

static_cast:用於非多態類型的轉換。

dynamic_cast:用於多態類型的轉換。

const_cast:用來消除const, volatile, __unaligned屬性的轉換。

reinterpret_cast:用於空間的從新解釋。

還有一個在VS2005中出現的類型轉換關鍵字safe_cast.#2

 

static_cast:

static_cast<type_id>(expression)

這個關鍵字能夠用來將一個指針轉換爲父類的指針也能夠轉換爲子類的指針或者基本的類型轉換。可是這種轉換是強制的,並無任何運行時類型檢查來保證轉換的正確性,因此編寫代碼的人須要明白本身所進行的轉換是否合理。

//基本類型的轉換

enum e { A = 1, B, C };

double d = 12.25;

unsigned int ui = 25;

char c = static_cast<char>(ui);

int i = static_cast<int>(d);

int j = static_cast<int>(B);

//父類子類轉換

class F                  //father

{

public:

    int _father;

};

class S : public F       //son

{

public:

    _son;

};

F *pFather = new F();

S *pSon = new S();

F *pF;

S *pS;

pF = static_cast<F *>(pSon);    //將子類指針轉換爲父類指針,OK

pS = static_cast<S *>(pFather); //將父類指針轉換爲子類指針,錯誤

第二個錯誤的轉換不是說編譯器編譯不過去,而是運行時會出現錯誤。

緣由以下:假設pF指向了pSon的位置,它能夠訪問_father,它找不到_son,這樣沒有問題。可是pS指向了pFather的位置,它訪問_father沒有問題,可是訪問_son時就會產生錯誤,由於pFather根本沒有_son這個變量。

下面是將父類轉換爲子類指針時,static_cast和dymanic_cast二者不一樣的表現:

class F

{

public:

    virtual void speak(){};

    int i;

};

 

class S : public F

{

public:

    void speak()

    {

       cout << "S = " << _s << endl;

    }

    double _s;

};

F *pF = new F();

S *pS = static_cast<S*>(pF);

pS->speak();

S1 *pDS = dynamic_cast<S*>(pF);

pDS->speak();

靜態的轉換編譯不顯示警告,運行結果不輸出(調用F的speak函數)。動態的轉換編譯顯示可能出現不可預期的結果,運行時崩潰。(VS2005時,返回空指針,可是不會崩潰。我認爲要是按照C++的特性仍是崩潰比較好一點,讓程序員容易理解這麼作是錯誤的。)

 

dynamic_cast:

dynamic_cast<type_id>(expression)

本關鍵字主要處理多態的類型轉換,type_id要麼是指針類型,要麼是引用類型要麼是void*。當type_id爲指針和void*時,expression必須是type_id類型的指針,當type_id爲引用時,expression也必須是type_id類型的引用。#1

 

1.最經常使用的用法就是將子類指針轉換爲父類指針。(不舉例)

2.當type_id爲void*時,指針指向整個對象的空間。

Class A;

A *pA = new A();

void *p = dynamic_cast<void*>(pA);

可是type_id不爲void*時,計算機就要在運行時檢查是否可以轉換。

3.跳級轉換。

class A{};

class B : public A{};

class C : public B{};

    A *pA;

    B *pB;

    C *pC = new C();

    pB = dynamic_cast<B*>(pD);  //逐級轉換OK

    pA = dynamic_cast<A*>(pB);  //逐級轉換OK

    或者

    pA = dynamic_cast<A*>(pC);  //跳級轉換OK

    delete pD;

如下狀況跳級轉換不能夠:


class A{};

class B : public A{};

class C : public A{};

class D : public B, public C{};

    A *pA;

    D *pD = new D();

    pA = dynamic_cast<A*>(pB);  //出現錯誤,是不行的,緣由你們都清楚。

 


class A{};

class B : public A{};

class C : public A{};

class D : public B{};

class E : public C, public D{};

    A *pA;

    B *pB;

    E *pE = new E();

    pB = dynamic_cast<B*>(pE);

    pA = dynamic_cast<A*>(pB);  //能夠

    pA = dynamic_cast<A*>(pE);  //不能夠,緣由是很簡單的。

    delete pE;

4.兩個不相干的類之間轉換。

class A {};

class B {};

    A* pa = new A;

    B* pb = dynamic_cast<B*>(pa);   // 不能夠,沒有相互轉換的基礎

可是reinterpret_cast能夠轉換,能夠參考reinterpret_cast

 

 

const_cast:

const_cast<type_id>(expression)

這個關鍵字消除了幾個關鍵字的做用const, volatile,和__unaligned的做用。const常用。MSDN有const的例子照抄過來。

class CCTest {

public:

   void setNumber( int );

   void printNumber() const;

private:

   int number;

};

void CCTest::setNumber( int num ) { number = num; }

void CCTest::printNumber() const {

   cout << "\nBefore: " << number;

   const_cast< CCTest * >( this )->number--;//這裏消除了const的做用

   cout << "\nAfter: " << number;

}

int main() {

   CCTest X;

   X.setNumber( 8 );

   X.printNumber();

}

 

reinterpret_cast:

reinterpret_cast

這個關鍵字比較「強悍」,隨意轉換類型。可是轉換錯誤,就是你的不對了。呵呵,個人原則兩個字:「慎用」。

這個關鍵字能夠在任何類型的指針之間轉換。

不能夠替代const_cast。

不提供安全轉換。

MSDN的例子顯示出來它的強悍,也顯示出了他的脆弱。只要你一個不當心就會亂用。

#include <iostream>

 

// Returns a hash code based on an address

unsigned short Hash( void *p ) {

   unsigned int val = reinterpret_cast<unsigned int>( p );

   return ( unsigned short )( val ^ (val >> 16));

}

 

using namespace std;

int main() {

   int a[20];

   for ( int i = 0; i < 20; i++ )

      cout << Hash( a + i ) << endl;

}

 

 

#1 dynamic_cast的type_id爲引用的狀況我不許備瞭解,好像是微軟VS2005的特性,而不是標準C++的特性。對於VS6.0我仍是感受比較欣賞的。雖然不如他的新版本那樣支持更多的C++特性,可是我本身的感受是VS的產品在無限的向C#靠攏,無限的向java的易用性靠攏,這樣的話C++程序在抑制到別的操做系統時就須要作很大的修改。這也是微軟的霸道之處。題外話:微軟的vista是一款失敗的產品,在vista上微軟開發了virtual PC 2007的虛擬機,可是這款產品只支持windows系統的產品安裝,對於linux產品他就不支持(只能安裝,不能用),由於他不支持24位真彩色。這就說明它的心態是封閉的,而封閉最終致使它的衰敗。

#2 safe_cast也是微軟的東西,想了解的請參考VS2005的MSDN。

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/callmeback/archive/2009/04/01/4040583.aspx

相關文章
相關標籤/搜索