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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中有四种强制类型转换,分别是reinterpret_cast、const_cast、static_cast和dynamic_cast。 reinterpret_cast用于进行底层的重新解释转换,可以将一个指针或引用转换为其他类型的指针或引用,甚至可以将指针转换为整数类型。但是使用reinterpret_cast需要非常小心,因为它是一种非常危险的操作,可能会导致未定义的行为。 const_cast用于移除const属性,可以将const修饰的变量或指针转换为非const类型。这可以用于去除const限定符,从而修改被const修饰的变量的值。 static_cast用于进行常见的类型转换,可以将一个表达式转换为另一种类型,例如基本数据类型之间的转换、父类指针或引用转换为子类指针或引用、以及void指针和任意类型的指针之间的转换。但是需要注意,在进行父类到子类的转换时,只有当父类指针或引用实际上指向了一个子类对象时,才能进行成功的转换。 dynamic_cast用于在继承关系中进行安全的向下转型(downcasting)。它可以将一个父类指针或引用转换为子类指针或引用,同时会进行类型检查,确保转换是安全的。如果转换失败,dynamic_cast会返一个空指针或抛出一个std::bad_cast异常。 这四种强制类型转换在不同的场景下有不同的应用,可以根据具体的需求选择合适的转换方式。但是需要注意,在使用这些强制类型转换时,一定要谨慎和慎重,确保转换的安全性和正确性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结](https://download.csdn.net/download/weixin_38629976/12808232)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [C++的四种类型转换reinterpret_cast/const_cast/static_cast /dynamic_cast](https://blog.csdn.net/salmonwilliam/article/details/113941785)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [C++四种cast转换(const_cast、static_cast、dynamic_cast、reinpreter_cast)类型转换运算符](https://blog.csdn.net/Dontla/article/details/130792118)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值