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
如果把类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,这篇文章推荐读一下