1. 程式人生 > >[C/C++]_[0基礎]_[static_cast,reinterpret_cast,dynimic_cast的使用場景和差別]

[C/C++]_[0基礎]_[static_cast,reinterpret_cast,dynimic_cast的使用場景和差別]

輸出 type class 可能 pen rgs make 在那 char


場景:

1. C++的對象差別於C的原因是他們能夠有繼承關系, 方法有重載, 覆蓋關系等, 他們的對象內存數據結構因此也比較復雜.

2. 非常多情況下我們須要一個父類來存儲子類的指針對象進行通用方法的操作。涉及到詳細某個子類對象特定操作時又須要強制轉換為子類。那麽這時候該用什麽好呢?

答: 假設不須要類型檢查的話就直接用C的強制轉換就可以(B*)c. 可是C++ 之父並不推薦使用C的強制類型轉換;

原因1是沒有編譯器檢查.

原因2是對象指針在子類父類之間轉換時所相應的地址值可能會變化, 這樣用C的轉換會有誤導的可能在那裏.


看樣例和凝視說明吧:

test.cpp

#include <iostream>

class A
{
public:
	A(){}
	~A(){}
	int i;
	int j1;
	void Test(){ std::cout << "TestA" << std::endl;}
	/* data */
};

class C
{
public:
	C(){}
	~C(){}
	int j;
	void Test(){ std::cout << "TestC" << std::endl;}
	/* data */
};

class B : public A,public C
{
public:
	B(){}
	~B(){}
	void Test(){ std::cout << "TestB" << std::endl;}
	/* data */
};

class K
{

};

// static_cast: 能夠進行類型上行和下行轉換,會進行類型檢查.
// reinterpret_cast: 和C的強轉一樣,不做類型檢查,能夠從隨意指針類型轉換為其它指針類型,非指針類型不能轉,比方char to int.
// dynimic_cast:  僅僅適用於多態的類(帶virtual)
int main(int argc, char const *argv[])
{
	A* a = new A();
	B* b = new B();
	C* c = b;

	std::cout << "(int*)a* :" << (int*)a << " (int)a:" << (int)a << " reinterpret_cast<int>(a):" 
		      << reinterpret_cast<int>(a) << std::endl;

	std::cout << "(int*)b :" << (int*)b << " (int)b:" << (int)b << " reinterpret_cast<int>(b):" 
		      << reinterpret_cast<int>(b) << std::endl;

	// 1.這裏假設把c轉換為(K*)c,編譯不會報錯,可是假設使用static_cast<K*>編譯會報錯.
	// 由於static_cast會進行上行的類型檢查.
    // 註意: 這裏(int*)c的地址和上邊的(int*)b地址是不一樣的,由於他們不是多態關系,並且A,C有成員變量,因此會有偏移量.(沒有virtual)
	std::cout << "(int*)c :" << (int*)c << " (int)c:" << (int)c << " reinterpret_cast<int>(c):" 
		      << reinterpret_cast<int>(c) <<  " (B*)c: " << (B*)c << " static_cast<B*>(c):" 
		      << static_cast<B*>(c) << " static_cast<C*>(b):" 
		      << static_cast<C*>(b)
		      << std::endl;

    // 下面編譯會報錯,dynimc_cast不同意非多態轉換,由於沒有virtual
	// ////error: cannot dynamic_cast ‘c‘ (of type ‘class C*‘) to type ‘class B*‘ (source type is not polymorphic)
	// 假設C的構造函數加virtual的話是能夠轉的,並且帶virtual表的地址不會變.
	// std::cout << "c* :" << (int*)c << ":" << (int)c << ":" 
	// 	      << dynamic_cast<B*>(c) << ":"
	// 	      << std::endl;	      
	return 0;
}

輸出:

(int*)a* :0x2c64e0 (int)a:2909408 reinterpret_cast<int>(a):2909408
(int*)b :0x2c2378 (int)b:2892664 reinterpret_cast<int>(b):2892664
(int*)c :0x2c2380 (int)c:2892672 reinterpret_cast<int>(c):2892672 (B*)c: 0x2c2378 static_cast<B*>(c):0x2c2378 static_cast<C*>(b):0x2c2380

所以你看到下面static_cast的使用方法不要認為奇怪, 它是為了使用編譯器檢查.

    template<typename T> void** IID_PPV_ARGS_Helper(T** pp) 
    {
        static_cast<IUnknown*>(*pp);    // make sure everyone derives from IUnknown
        return reinterpret_cast<void**>(pp);
    }



參考:

http://www.cnblogs.com/chio/archive/2007/07/18/822389.html



[C/C++]_[0基礎]_[static_cast,reinterpret_cast,dynimic_cast的使用場景和差別]