关于对象切片Thinking in C++中有这么一段话

英文原版:

If you upcast to an object instead of a pointer or reference,
something will happen that may surprise you: the object is “sliced”
until all that remains is the subobject that corresponds to the
destination type of your cast.

对于绿色这一段话,有些书译为:这个对象被”切片”,直到剩下的是适合于目的的子对象。//有点晦涩。。。

我的理解是:这个对象将被”分割”成只剩下与目的类型(即:转换以后的类型)相匹配的子对象(即:成员变量和函数)

这句话的意思也就是说:在函数传参处理多态性时,如果一个派生类对象在UpCasting时,用的是传值的方式,而不是指针和引用,那么,这个派生类对象在UpCasting以后,将会被slice(切分)成基类对象,也就是说,派生类中独有的成员变量和方法都被slice掉了,值剩下和基类相同的成员变量和属性。这个派生类对象被切成了一个基类对象。

那么我们来看个实例,真正理解什么是对象切片,代码如下:摘自Thiking In C++

//: C15:ObjectSlicing.cpp #include <iostream> #include <string> using namespace std; class Pet { string pname; public: Pet(const string& name) : pname(name) {} virtual string name() const { return pname; } virtual string description() const { return "This is " + pname; } }; class Dog : public Pet { string favoriteActivity; public: Dog(const string& name, const string& activity) : Pet(name), favoriteActivity(activity) {} string description() const { return Pet::name() + " likes to " + favoriteActivity; } }; void describe(Pet p) { // Slices the object cout << p.description() << endl; } int main() { Pet p("Alfred"); Dog d("Fluffy", "sleep"); describe(p); //正常调用基类函数 describe(d); //对象切片 }

在Slice前后,Dog类对象d的变化如下图:

注意到after Slice以后,虚函数表指针时Pet vptr,Dog类的favoriteActivity成员变量也不存在了。

其实这时候执行了一些步骤:

在正常情况下,main函数中执行describe函数,在传递Dog对象d的时候,调用了Pet类的拷贝构造函数,相当于此时,在describe函数中的那个Pet类对象p是拷贝构造的结果,所以,跟Dog对象d已经没有了关系。所以,此时,p.description()执行的会是调用的基类也就是Pet类的description函数。而也许,这并不是你所想要看见的结果(因为,你或许是想实现多态调用)

但是,此例中,恰恰因为Pet类中的description函数被声明为纯虚函数,它是不能被创建实例的,所以,在全局的describe函数中不可能有者拷贝构造函数来实例化一个Pet类对象。所以,此时,编译器就会报错。

而这种情况,也是纯虚函数存在的一个重要意义:避免对象切片。

纯虚函数的一个重要意义,就在于可以在编译期间避免对象切片,从而避免很多可能会出现的问题。

什么是对象切片(Object Slicing)?相关推荐

  1. 对象切片(object slicing)和多态

    在函数传参处理多态性时,如果一个派生类对象在UpCasting时,用的是传值的方式,而不是指针和引用,那么,这个派生类对象在UpCasting以后,将会被slice成基类对象.https://www. ...

  2. C++ 进阶——object slicing 与虚函数与dynamic_cast

    C++基础--C++风格的类型转换(static_cast.const_cast.dynamic_cast.reinterpret_cast) 只有再做向上转型(upcast)的动作时,才存在对象切割 ...

  3. JavaScript 复制对象与Object.assign方法无法实现深复制

    在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...

  4. 《JavaScript启示录》——1.21 JavaScript对象和Object()对象

    本节书摘来自异步社区<JavaScript启示录>一书中的第1章,第1.21节,作者:[美]Cody Lindley著,更多章节内容可以访问云栖社区"异步社区"公众号查 ...

  5. Python编程基础:第七节 字符串切片String Slicing

    第七节 字符串切片String Slicing 前言 实践 前言 我们有时候需要对一个字符串进行切片,取其一部分作为新的字符串进行处理.例如从姓名中分别提取姓和名,从网站域名中提取网站名称等等. 实践 ...

  6. JVM - 剖析Java对象头Object Header之指针压缩

    文章目录 Pre 指针压缩 论证压缩效果 UseCompressedOops & UseCompressedClassPointers [指针压缩]开启 VS 关闭 指针压缩的目的 为什么堆内 ...

  7. JVM - 剖析Java对象头Object Header之对象大小

    文章目录 Pre 总览 对象头剖析 查看对象内存的占用情况 对象头C++源码 注释 Pre JVM - 写了这么多年代码,你知不道new对象背后的逻辑? 中大体介绍了Java中 new 对象背后的主要 ...

  8. linux 进程间通信 dbus-glib【实例】详解三 数据类型和dteeth(类型签名type域)(层级结构:服务Service --> Node(对象、object) 等 )(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  9. C++构造与析构(18) - 静态对象(static object)何时销毁

    C++的static关键字 static关键字可以用于修改局部变量,函数,类的数据成员以及对象.静态局部变量只初始化一次,然后在每次函数调用时都保持它的值.静态成员函数可以直接用类来调用,不需要创建对 ...

最新文章

  1. Linux开机启动顺序
  2. java 局部性原理_程序局部性原理
  3. data too long for column 'Auser' at row 1
  4. 华为杯数学建模优秀论文_数学建模经典例题(2016年国赛B题与优秀论文)
  5. Undefined symbols for architecture i386的错误
  6. MicroSIP编译完全手册
  7. 哈夫曼编码c语言例题,关于哈夫曼编码试题的计算
  8. PHP 实现网页爬虫
  9. mysql数据库熔断_服务熔断
  10. 怎么使计算机桌面整洁,如何管理电脑桌面,让桌面清洁,干净,大气......
  11. 一入编码深似海,在达观数据做程序员是怎样一种体验?
  12. 单相全桥逆变原理及仿真实验
  13. 无法完成请求,因为暂存盘已满怎么办?
  14. 发展新机遇!内蒙古长山壕金矿迎来浙江广泰黄金考察团
  15. 2016新华三杯复赛实验试题
  16. Linux/Android下的虚拟声卡
  17. Maxon收购Redshift Rendering Technologies
  18. java的面试题总结
  19. 【连载】跨越时代的度量衡——Pandora.js 的 Metrics 介绍
  20. c 如何操作php,如何用PHP实现通过Web执行C/C++程序

热门文章

  1. 下雨天,适合学「Spring Boot」
  2. 最新游戏陪玩语音聊天系统源码+视频搭建教程
  3. 丢手帕问题(约瑟夫问题-数组实现)
  4. DCT 变换的一些思考
  5. Unity 群聚(生成鱼群)
  6. java中多态的作用,多态的好处,以及为什么要用多态?
  7. 一本通 1184:明明的随机数 1187:统计字符数 提示:桶排 (爸爸)
  8. [4]Python数据类型【1】
  9. QuickRedis 是一款 Redis 可视化管理工具
  10. mysql5.7 优化 三