c++強制轉換之dynamic_cast

dynamic_cast<type-id>(expression)

用法:該運算符把expression轉換成type-id類型的對象。Type-id必須是類的指針、類的引用或者void*;如果type-id是指針類型,那麼expression也必須是一個指針,如果type-id是一個引用,那麼expression也必須是一個引用。

      dynamic-cast運算符可以在執行期間決定真正的類型。如果下行轉換是安全的(如果基類指針或者引用確實指向一個派生類對象),這個運算符會傳回適當轉型過得指針;如果下行轉換不安全,那麼運算符會傳回空指針(基類指針或者引用沒有指向一個派生類對象)。


例子1

#include <stdio.h>
#include <string>
using namespace std;

class A
{
public:
	A(int i) : m_a(i)
	{
	}

	~A() {}

	virtual void Test() { printf("A Test\n"); }
private:
	int m_a;
};

class B : public A
{
public:
	B() : A(1)
	{
	}
	virtual ~B() {}

	virtual void Test() { printf("B Test\n"); }

};

int main(int argc, char** argv)
{
	B* pb1 = new B();
	A* pa1 = dynamic_cast<A*>(pb1);
	printf("pa1: %p, pb1: %p\n", pa1, pb1);
	if (pa1 != NULL)
	{
		pa1->Test();
	}
	else
	{
		printf("pa1 is NULL\n");
	}

	A* pa2 = new A(1);
	B* pb2 = dynamic_cast<B*>(pa2);
	printf("pa2: %p, pb2: %p\n", pa2, pb2);
	if (pb2 != NULL)
	{
		pb2->Test();
	}
	else
	{
		printf("pb2 is NULL\n");
	}

	B* pb3 = new B();
	A* pa3 = dynamic_cast<A*>(pb3);
	pb3 = dynamic_cast<B*>(pa3);
	printf("pa3: %p, pb3: %p\n", pa3, pb3);
	if (pa3 != NULL)
	{
		pa3->Test();
	}
	else
	{
		printf("pa3 is NULL\n");
	}

	delete pa1;
	delete pa2;
	delete pb3;
	getchar();
	return 0;
}

結果如下:

pa1: 005EB430, pb1: 005EB430
B Test
pa2: 005EC4B8, pb2: 00000000
pb2 is NULL
pa3: 005EC500, pb3: 005EC500
B Test

分析:上行轉換沒什麼問題,下行轉換隻有在初始指針是B*類型的時候才成功轉換

如果把類A的虛成員函數Test()改成非虛成員函數,則第二次轉換和第四次轉換編譯時會出現錯誤:error C2683: “dynamic_cast”:“A”不是多態類型,所以下行轉換時基類(子類可以不定義虛成員函數)必須有虛成員函數才能轉換。


例子2

#include <stdio.h>
#include <string>
using namespace std;

class A
{
public:
	A(int i) : m_a(i)
	{
		printf("A construction\n");
	}

	void Print()
	{
		printf("m_a: %d\n", *((int*)this));
		//printf("%d\n", m_a);
	}

	A(const A& a)
	{
		printf("copy construction\n");
		this->m_a = a.m_a;
	}
	~A() {}

private:
	int m_a;
};

class B : public A
{
public:
	B() : A(1)
	{
	}
	virtual ~B() {}

	virtual void Test() { printf("B Test\n"); }

};

int main(int argc, char** argv)
{
	B b;
	printf("\n");
	A& a1 = dynamic_cast<A&>(b);
	printf("pa1: %p, pb: %p\n", &a1, &b);
	printf("\n");
	A a2 = dynamic_cast<A&>(b);
	printf("pa2: %p, pb: %p\n", &a2, &b);
	getchar();
	return 0;
}

運行結果

A construction

pa1: 003AFB40, pb: 003AFB3C

copy construction
pa2: 003AFB24, pb: 003AFB3C


例子3

#include <stdio.h>
#include <string>
using namespace std;

class A
{
public:
	A(int i) : m_a(i)
	{
	}

	~A()
	{
		printf("A destruction\n");
	}

private:
	int m_a;
};

class B : public A
{
public:
	B() : A(1)
	{
		ch = new char[10];
	}
	~B()
	{
		printf("B destruction\n");
		delete ch;
	}

private:
	char* ch;
};

int main(int argc, char** argv)
{
	B* b = new B();
	A* a = dynamic_cast<A*>(b);
	if (a != NULL)
	{
		delete a;
		//delete b;
	}
	getchar();
	return 0;
}
運行結果爲:

A destruction

子類的部分並沒有釋放,所以我們在強制轉換的時候,任何時刻都不要試圖去釋放轉換後的指針,否則可能會造成內存泄露,要釋放原來的指針。


例子4

#include <stdio.h>
#include <string>
using namespace std;

class A
{
public:
	A(int i) : m_a(i)
	{
	}

	~A()
	{
		printf("A destruction\n");
	}

	virtual void Test() { printf("Test\n"); }
private:
	int m_a;
};

int main(int argc, char** argv)
{
	A* pa = new A(1);
	void* v = dynamic_cast<void*>(pa);
	delete pa;
	getchar();
	return 0;
}

#include <stdio.h>
#include <string>
using namespace std;

class A
{
public:
	A(int i) : m_a(i)
	{
	}

	~A()
	{
		printf("A destruction\n");
	}

	void Test() { printf("Test\n"); }
private:
	int m_a;
};

int main(int argc, char** argv)
{
	A* pa = new A(1);
	void* v = dynamic_cast<void*>(pa);
	delete pa;
	getchar();
	return 0;
}

#include <stdio.h>
#include <string>
using namespace std;

class A
{
public:
	A(int i) : m_a(i)
	{
	}

	~A()
	{
		printf("A destruction\n");
	}

	virtual void Test() { printf("Test\n"); }
private:
	int m_a;
};

int main(int argc, char** argv)
{
	void* v = new A(1);
	A* pa = dynamic_cast<A*>(v);
	delete pa;
	getchar();
	return 0;
}

結果:第一段代碼編譯成功運行也沒問題,第二段代碼編譯失敗:error C2683: “dynamic_cast”:“A”不是多態類型,第三段代碼編譯失敗:error C2681: “void *”: dynamic_cast 的無效表達式類型。

由此可見,類對象指針要轉換爲void*型,同樣類也要用於虛成員函數;void*不能當做表達式


例子5

class A
{
public:
	int m_iNum;
	virtual void f(){}
};

class B: public A
{
};
  
class D: public A
{
};

void foo()
{
	B* pb = new B;
	pb->m_iNum = 100;
	D* pd1 = static_cast<D*>(pb);		//compile error
	D* pd2 = dynamic_cast<D*>(pb);		//pd2 is NULL
	delete pb;
}

dynamic_cast支持交叉轉換,static_cast不支持,編譯時會出錯,dynamic_cast轉換後返回空指針


參考:http://www.cnblogs.com/jerry19880126/archive/2012/08/14/2638192.html,這篇文章推薦讀一下

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章