您的位置:首页 > 编程语言 > C语言/C++

c++强制转换之dynamic_cast

2016-04-20 02:44 567 查看
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,这篇文章推荐读一下
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: