c++強制変換のdynamic_cast

5590 ワード

dynamic_cast(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
"); } private: int m_a; }; class B : public A { public: B() : A(1) { } virtual ~B() {} virtual void Test() { printf("B Test
"); } }; int main(int argc, char** argv) { B* pb1 = new B(); A* pa1 = dynamic_cast<A*>(pb1); printf("pa1: %p, pb1: %p
", pa1, pb1); if (pa1 != NULL) { pa1->Test(); } else { printf("pa1 is NULL
"); } A* pa2 = new A(1); B* pb2 = dynamic_cast<B*>(pa2); printf("pa2: %p, pb2: %p
", pa2, pb2); if (pb2 != NULL) { pb2->Test(); } else { printf("pb2 is NULL
"); } B* pb3 = new B(); A* pa3 = dynamic_cast<A*>(pb3); pb3 = dynamic_cast<B*>(pa3); printf("pa3: %p, pb3: %p
", pa3, pb3); if (pa3 != NULL) { pa3->Test(); } else { printf("pa3 is NULL
"); } 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()を非ダミーメンバー関数に変更すると、2回目の変換と4回目の変換コンパイルでエラーが発生します:error C 2683:“dynamic_cast”:“A”はマルチステートタイプではありませんので、下り変換時にベースクラス(サブクラスはダミーメンバー関数を定義しないことができます)はダミーメンバー関数でなければ変換できません.
例2
#include <stdio.h>
#include <string>
using namespace std;

class A
{
public:
	A(int i) : m_a(i)
	{
		printf("A construction
"); } void Print() { printf("m_a: %d
", *((int*)this)); //printf("%d
", m_a); } A(const A& a) { printf("copy construction
"); 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
"); } }; int main(int argc, char** argv) { B b; printf("
"); A& a1 = dynamic_cast<A&>(b); printf("pa1: %p, pb: %p
", &a1, &b); printf("
"); A a2 = dynamic_cast<A&>(b); printf("pa2: %p, pb: %p
", &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
"); } private: int m_a; }; class B : public A { public: B() : A(1) { ch = new char[10]; } ~B() { printf("B destruction
"); 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
"); } virtual void Test() { printf("Test
"); } 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
"); } void Test() { printf("Test
"); } 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
"); } virtual void Test() { printf("Test
"); } 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; }

結果:第1セグメントコードコンパイルが正常に実行されても問題なく、第2セグメントコードコンパイルに失敗した:error C 2683:“dynamic_cast”:“A”はマルチステートタイプではなく、第3セグメントコードコンパイルに失敗した:error C 2681:“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_キャスト変換後に空のポインタに戻る
参照先:http://www.cnblogs.com/jerry19880126/archive/2012/08/14/2638192.htmlあ、この文章はお勧めです.