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

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数