C++中的对象切割(Object slicing)问题

2023-10-09 17:12

本文主要是介绍C++中的对象切割(Object slicing)问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 在C++中,当我们把派生类对象向上强制转型为基类对象时,会造成对象切割(Object slicing)问题。
 请看下面示例代码:

#include <iostream>
using namespace std;class CBase {
public:virtual ~CBase() = default;virtual void foo() {printf("print in Class CBase,this address:%p\n", this);}
};class CDerive : public CBase {
public:virtual void foo() override {printf("print in Class CDerive,this address:%p\n", this);}
};int main() 
{CBase base;CDerive derive;CBase* pBase = &derive;cout << "\n本次调用的是pBase->CBase::foo()\n\t";pBase->CBase::foo();cout << "\n本次调用的是pBase->foo()\n\t";pBase->foo();cout << "\n本次调用的是 (static_cast<CBase>(derive)).foo() \n\t";(static_cast<CBase>(derive)).foo();
}

 代码运行结果如下:
在这里插入图片描述
 对于前两次调用成员函数foo的结果,大家应该都清楚,pBase是指向派生类对象的基类指针,而foo成员函数是虚函数;因此 pBase->foo() 调用的是派生类方法;pBase->CBase::foo()由于指定了调用CBase的foo函数,因此调用的是基类方法。另外,foo函数打印出来的this指针的地址,显示前两次调用的this指针是同一个,也就是指向子类对象derive。
 关键是最后一次调用的结果,显示调用的是基类方法,并且对象的地址也不是子类对象derive的地址。它的调用语句是:

(static_cast<CBase>(derive)).foo();

 这是为什么呢?这涉及到对象切割(object slicing)。
 在编译时,编译器看到这句是要将派生类对象derive向上强制转为基类对象,因此编译器以所谓的拷贝构造函数把derive中的CBase成分拷贝一份,并把拷贝好的副本作为临时对象放在内存中。在运行期,这个副本(它是CBase对象)调用foo函数时,当然调用的是CBase::foo成员函数了!
 请注意,如果我们把派生类对象的指针向上强制转为基类对象的指针,那么转换后的基类指针仍然指向派生类对象。
 总之,当我们把派生类对象向上强制转型为基类对象时,会经历对象切割(Object slicing),也就是:编译器在内存中创建了一个子类对象的基类成分的副本,这个临时对象与之前的子类对象无关。

这篇关于C++中的对象切割(Object slicing)问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/174338

相关文章

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

oracle数据库索引失效的问题及解决

《oracle数据库索引失效的问题及解决》本文总结了在Oracle数据库中索引失效的一些常见场景,包括使用isnull、isnotnull、!=、、、函数处理、like前置%查询以及范围索引和等值索引... 目录oracle数据库索引失效问题场景环境索引失效情况及验证结论一结论二结论三结论四结论五总结ora

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

element-ui下拉输入框+resetFields无法回显的问题解决

《element-ui下拉输入框+resetFields无法回显的问题解决》本文主要介绍了在使用ElementUI的下拉输入框时,点击重置按钮后输入框无法回显数据的问题,具有一定的参考价值,感兴趣的... 目录描述原因问题重现解决方案方法一方法二总结描述第一次进入页面,不做任何操作,点击重置按钮,再进行下

解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

《解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题》本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常... 目录myBATis-plus-boot-starpythonter与mybatis-spring-b

mysql主从及遇到的问题解决

《mysql主从及遇到的问题解决》本文详细介绍了如何使用Docker配置MySQL主从复制,首先创建了两个文件夹并分别配置了`my.cnf`文件,通过执行脚本启动容器并配置好主从关系,文中还提到了一些... 目录mysql主从及遇到问题解决遇到的问题说明总结mysql主从及遇到问题解决1.基于mysql

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

如何安装HWE内核? Ubuntu安装hwe内核解决硬件太新的问题

《如何安装HWE内核?Ubuntu安装hwe内核解决硬件太新的问题》今天的主角就是hwe内核(hardwareenablementkernel),一般安装的Ubuntu都是初始内核,不能很好地支... 对于追求系统稳定性,又想充分利用最新硬件特性的 Ubuntu 用户来说,HWEXBQgUbdlna(Har

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo