前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【C++】类型转换 ④ ( 子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast )

【C++】类型转换 ④ ( 子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast )

作者头像
韩曙亮
发布2023-11-28 11:22:11
3490
发布2023-11-28 11:22:11
举报

在之前写过一篇 C++ 类型转换的博客 【C++ 语言】类型转换 ( 转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast | 字符串转换 ) , 简单介绍了 C++ 类型转换 ;

在 博客 【C++】类型转换 ① ( C 中的类型转换 | C++ 类型转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast ) 将 C 语言 和 C++ 中的类型转换进行了对比 ;

在 博客 【C++】类型转换 ② ( C++ 静态类型转换 static_cast | C 语言隐式转换弊端 | 代码示例 ) 中 , 主要分析了 静态类型转换 static_cast , 可以解决 C 语言隐式转换的弊端 ;

在博客 【C++】类型转换 ③ ( 重新解释类型转换 reinterpret_cast | 指针类型数据转换 ) 分析了 指针数据类型的转换 , 在 C 语言环境下 , 可以使用显示强制类型转换 , 在 C++ 环境中只能使用 重新解释类型转换 reinterpret_cast ;

本篇博客中 , 分析 C++ 环境下 使用 各种方式 进行 父类 和 子类 类型之间的转换 , 推荐使用 动态类型转换 dynamic_cast ;

一、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast


C++ 面向对象 应用场景中 , 涉及到 父类 和 子类 之间的转换 ;

很明显 C 语言的 强制类型转换 , 不管是 隐式 还是 显示 转换 , 都无法转换 C++ 对象的类型 ;

动态类型转换 dynamic_cast 一般用于 父类 ( 对象 / 指针 / 引用 ) 和 子类 ( 对象 / 指针 / 引用 ) 之间的转换 , 是 C++ 语言特有的 , C 语言中没有该转换类型 ;

1、构造父类和子类

编写一个 父类 , 其中定义一个纯虚函数 ;

再编写两个 子类 , 重写 父类的 纯虚函数 , 每个子类再 各自定义一个 特有的函数 ;

代码语言:javascript
复制
// 父类
class Father
{
public:
	virtual void say() = 0;
};

// 子类
class Son : public Father
{
public:
	void say()
	{
		cout << "Son" << endl;
	}

	// Son 子类的特有函数
	void son_say()
	{
		cout << "son_say" << endl;
	}
};

// 子类2
class Son2 : public Father
{
public:
	void say()
	{
		cout << "Son2" << endl;
	}

	// Son2 子类的特有函数
	void son2_say()
	{
		cout << "son2_say" << endl;
	}
};

2、子类 和 父类 之间的类型转换 - 隐式类型转换

先创建 子类对象 ,

将子类对象的 地址赋值给 父类指针 , 其中包含了 隐式转换 ;

在下面的代码中 , 使用取地址符获取 Son 类型 子类对象的地址 , 指针类型是 Son* 类型 , 将该类型值 赋值给 Father* 指针 , 其中进行了 隐式类型转换 ;

代码语言:javascript
复制
	Son son;

	// 创建父类指针 , 直接让父类指针指向子类对象
	// 不会报错 , 但是这么做有一定的风险
	Father* pFather = NULL;
	// 隐式类型转换
	pFather = &son;

此外 , 函数接收 父类指针形参 作为参数 , 如果调用该函数 , 传入子类指针 , 此时涉及到将 子类指针 Son* 隐式转为 父类指针 Father* ;

代码语言:javascript
复制
// 函数接收 父类对象 作为参数, 可传入子类对象
void objSay(Father* obj)
{
}

// 调用函数, 传入子类对象指针
objSay(&son);

3、子类 和 父类 之间的类型转换 - 静态类型转换 static_cast

静态类型转换 static_cast , 可以在 C++ 编译器 编译时 对类型转换 进行检查 ;

如果 转换的类型不匹配 , 就会在编译时报错 , 避免出现更大的错误 ;

下面的代码中 , 使用取地址运算符 &son 获取 的 Son* 类型的 指针 , 将其使用 静态类型转换 static_cast 转为 Father* 类型的指针 ,

在 C++ 编译器编译阶段 , 会对类型进行检测 , 如果通过检测 , 则可以编译成功 , 如果类型错误 , 则会出现编译时报错的情况 ;

代码语言:javascript
复制
	Son son;

	// 创建父类指针 , 直接让父类指针指向子类对象
	// 不会报错 , 但是这么做有一定的风险
	Father* pFather = NULL;

	// 静态类型转换 static_cast,  可以在编译时 对类型转换 进行检查
	pFather = static_cast<Father*>(&son);

下面的代码就是 执行静态类型转换 检查出错的情况 ,

Son 和 Son2 都是 Father 的子类 , 二者之间不能相互转化 , 只能是 父类 和 子类 之间进行相互转换 ;

类型转换错误报错 : error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *” ;

代码语言:javascript
复制
	Son son;
	Son2 son2;

	// 创建父类指针 , 直接让父类指针指向子类对象
	// 不会报错 , 但是这么做有一定的风险
	Father* pFather = NULL;

	// 静态类型转换 static_cast,  可以在编译时 对类型转换 进行检查
	pFather = static_cast<Father*>(&son);

	// 类型转换错误报错 : error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”
	// message : 与指向的类型无关;
	//		强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换
	Son2* pSon2 = static_cast<Son2*>(&son);

执行后 , 出现如下报错 :

代码语言:javascript
复制
已启动生成…
1>------ 已启动生成: 项目: HelloWorld, 配置: Debug Win32 ------
1>Test.cpp
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(92,39): error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(92,16): message : 与指向的类型无关;强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换
1>已完成生成项目“HelloWorld.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

完整代码示例 :

代码语言:javascript
复制
#include "iostream"
using namespace std;

// 父类
class Father
{
public:
	virtual void say() = 0;
};

// 子类
class Son : public Father
{
public:
	void say()
	{
		cout << "Son" << endl;
	}

	// Son 子类的特有函数
	void son_say()
	{
		cout << "son_say" << endl;
	}
};

// 子类2
class Son2 : public Father
{
public:
	void say()
	{
		cout << "Son2" << endl;
	}

	// Son2 子类的特有函数
	void son2_say()
	{
		cout << "son2_say" << endl;
	}
};

// 函数接收 父类对象 作为参数, 可传入子类对象
void objSay(Father* obj)
{
	// 调用 父类 纯虚函数 可发生多态调用
	// 传入不同的子类 调用的是不同的函数
	obj->say();
}

int main() {

	Son son;
	Son2 son2;

	// 创建父类指针 , 直接让父类指针指向子类对象
	// 不会报错 , 但是这么做有一定的风险
	Father* pFather = NULL;

	// 静态类型转换 static_cast,  可以在编译时 对类型转换 进行检查
	pFather = static_cast<Father*>(&son);

	// 类型转换错误报错 : error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”
	// message : 与指向的类型无关;
	//		强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换
	Son2* pSon2 = static_cast<Son2*>(&son);

	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
};

执行结果 :

代码语言:javascript
复制
已启动生成…
1>------ 已启动生成: 项目: HelloWorld, 配置: Debug Win32 ------
1>Test.cpp
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(92,39): error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Test.cpp(92,16): message : 与指向的类型无关;强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换
1>已完成生成项目“HelloWorld.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
在这里插入图片描述
在这里插入图片描述

4、子类 和 父类 之间的类型转换 - 重新解释类型转换 reinterpret_cast

C++ 中 父类 和 子类 之间类型转换 , 还可以使用 重新解释类型转换 reinterpret_cast ;

下面的代码中 , 将 Son* 指针类型 重新解释为 Father* 指针类型 ;

代码语言:javascript
复制
	// C++ 强制类型转换 , 重新解释类型转换 reinterpret_cast
	pFather = reinterpret_cast<Father*>(&son);
	pFather->say();

5、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast

动态类型转换 dynamic_cast , 一般用于 子类 和 父类 之间的类型转换 ,

  • 运行时 , 如果类型转换成功 , 则进行转换 ;
  • 运行时 , 如果类型转换失败 , 则返回转换结果 NULL ;

借助上述特性 , 动态类型转换 dynamic_cast 可用于在 运行时 识别对象类型 ;

将 对象 强转为 指定类型对象, 如果失败了, 转换结果为 NULL , 说明被转换的对象 不是 指定类型的对象 ;

下面代码的作用是 : 将Father* obj 父类对象 强转为 Son* 子类对象 ,

  • 如果转换成功, 说明 obj 对象就是 Son 子类对象 , 则执行 Son 子类对象特有的函数 ;
  • 如果转换失败, 说明不是 Son 子类对象, 转换结果是 NULL , 也就是 0 , 后续不再处理 ;
代码语言:javascript
复制
	// 将Father* obj 父类对象 强转为 Son* 子类对象
	// 如果转换成功, 说明 obj 对象就是 Son 子类对象
	// 如果转换失败, 说明不是 Son 子类对象, 转换结果是 NULL , 也就是 0
	Son* son = dynamic_cast<Son*>(obj);
	if (son != NULL)
	{
		// 转换成功
		// 执行 Son 特有工作
		son->son_say();
	}

完整代码 , 参考下面章节的 完整代码示例 ;

二、完整代码示例


1、代码示例

代码语言:javascript
复制
#include "iostream"
using namespace std;

// 父类
class Father
{
public:
	virtual void say() = 0;
};

// 子类
class Son : public Father
{
public:
	void say()
	{
		cout << "Son" << endl;
	}

	// Son 子类的特有函数
	void son_say()
	{
		cout << "son_say" << endl;
	}
};

// 子类2
class Son2 : public Father
{
public:
	void say()
	{
		cout << "Son2" << endl;
	}

	// Son2 子类的特有函数
	void son2_say()
	{
		cout << "son2_say" << endl;
	}
};

// 函数接收 父类对象 作为参数, 可传入子类对象
void objSay(Father* obj)
{
	// 调用 父类 纯虚函数 可发生多态调用
	// 传入不同的子类 调用的是不同的函数
	obj->say();

	// 动态类型转换 dynamic_cast
	// 可用于在 运行时 识别对象类型
	// 将 对象 强转为 指定类型对象, 如果失败了, 转换结果为 NULL

	// 将Father* obj 父类对象 强转为 Son* 子类对象
	// 如果转换成功, 说明 obj 对象就是 Son 子类对象
	// 如果转换失败, 说明不是 Son 子类对象, 转换结果是 NULL , 也就是 0
	Son* son = dynamic_cast<Son*>(obj);
	if (son != NULL)
	{
		// 转换成功
		// 执行 Son 特有工作
		son->son_say();
	}

	// 将Father* obj 父类对象 强转为 Son2* 子类对象
	// 如果转换成功, 说明 obj 对象就是 Son2 子类对象
	// 如果转换失败, 说明不是 Son2 子类对象, 转换结果是 NULL , 也就是 0
	Son2* son2 = dynamic_cast<Son2*>(obj);
	if (son2 != NULL)
	{
		// 转换成功
		// 执行 Son2 特有工作
		son2->son2_say();
	}
}

int main() {

	Son son;
	Son2 son2;

	// 创建父类指针 , 直接让父类指针指向子类对象
	// 不会报错 , 但是这么做有一定的风险
	Father* pFather = NULL;

	// 静态类型转换 static_cast,  可以在编译时 对类型转换 进行检查
	pFather = static_cast<Father*>(&son);

	// 类型转换错误报错 : error C2440: “static_cast”: 无法从“Son *”转换为“Son2 *”
	// message : 与指向的类型无关;
	//		强制转换要求 reinterpret_cast、C 样式强制转换或函数样式强制转换
	//Son2* pSon2 = static_cast<Son2*>(&son);

	// C++ 强制类型转换 , 重新解释类型转换 reinterpret_cast
	pFather = reinterpret_cast<Father*>(&son);
	pFather->say();

	// 动态类型转换示例
	objSay(&son);
	objSay(&son2);


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
};

2、执行结果

执行结果 :

Son Son son_say Son2 son2_say Press any key to continue . . .

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast
    • 1、构造父类和子类
      • 2、子类 和 父类 之间的类型转换 - 隐式类型转换
        • 3、子类 和 父类 之间的类型转换 - 静态类型转换 static_cast
          • 4、子类 和 父类 之间的类型转换 - 重新解释类型转换 reinterpret_cast
            • 5、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast
            • 二、完整代码示例
              • 1、代码示例
                • 2、执行结果
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档