对象切片,有优势吗?

2024-04-24

对象切片是指当子类被分配给基类时,对象失去一些属性或功能。 就像是

Class A{

}
Class B extends A{

}

Class SomeClass{
A a = new A();
B b = new B();

// Some where if might happen like this */
a = b; (Object slicing happens)

}

我们说对象切片有什么好处吗? 如果是,有人可以告诉我对象切片对开发有何帮助以及它在哪些方面可能有帮助吗?


在 C++ 中,您应该将对象切片视为转换从派生类型到基类型[*]。一个全新的物体被创造出来,其“灵感来自于一个真实的故事”。

有时这是您想要做的事情,但结果在任何意义上都与原始对象不同。当对象切片出错时,人们没有注意,并认为它是同一个对象或其副本。

通常这没有什么好处。事实上,当有人本打算通过引用传递时却通过值传递,这通常是意外完成的。

很难举出一个例子来说明何时切片绝对是正确的做法,因为很难(尤其是在 C++ 中)举出一个非抽象基类绝对是正确的做法的例子。这是一个重要的设计点,不能轻易忽略 - 如果您发现自己有意或无意地切片了一个对象,很可能您的对象层次结构一开始就是错误的。要么基类不应该用作基类,要么它应该至少有一个纯虚函数,因此不能按值切片或传递。

因此,我给出的任何将对象转换为其基类的对象的示例都会正确地引发反对意见,“等一下,您首先要从具体类继承做什么?”。如果切片是偶然的,那么它可能是一个错误,如果是故意的,那么它可能是“代码味道”。

但答案可能是“是的,好的,这个不应该事物的结构确实如此,但考虑到它们are以这种方式构造,我需要从派生类转换为基类,并且根据定义,这是一个切片”。本着这种精神,这里有一个示例:

struct Soldier {
    string name;
    string rank;
    string serialNumber;
};

struct ActiveSoldier : Soldier {
    string currentUnit;
    ActiveSoldier *commandingOfficer; // the design errors multiply!
    int yearsService;
};

template <typename InputIterator>
void takePrisoners(InputIterator first, InputIterator last) {
    while (first != last) {
        Soldier s(*first);
        // do some stuff with name, rank and serialNumber
       ++first;
    }
}

现在,要求takePrisoners函数模板的特点是它的参数是一个可转换为 Soldier 类型的迭代器。它不一定是派生类,并且我们不直接访问成员“名称”等,因此takePrisoners考虑到以下限制,我们试图提供最简单的接口来实现:(a) 应该与 Soldier 一起使用,(b) 应该可以编写它也可以使用的其他类型。

ActiveSoldier 就是另一种类型。由于只有该类的作者最清楚的原因,它选择公开继承 Soldier,而不是提供重载的转换运算符。我们可以争论这是否是一个好主意,但我们假设我们坚持这样做。因为它是派生类,所以它可以转换为 Soldier。这种转换称为切片。因此,如果我们调用takePrisoners通过在begin() and end()ActiveSoldiers 向量的迭代器,然后我们将对其进行切片。

您可能会为 OutputIterator 提出类似的示例,其中接收者只关心正在传递的对象的基类部分,因此允许在将它们写入迭代器时对它们进行切片。

之所以有“代码味道”,是因为我们应该考虑 (a) 重写 ActiveSoldier,以及 (b) 更改 Soldier,以便可以使用函数而不是成员访问来访问它,这样我们就可以将这组函数抽象为一个接口,其他类型可以独立实现,这样takePrisoners不必转为士兵。其中任何一个都将消除对切片的需求,并且对于将来可以轻松扩展我们的代码具有潜在的好处。

[*]因为它是一个。下面的最后两行正在做同样的事情:

struct A {
    int value;
    A(int v) : value(v) {}
};

struct B : A {
    int quantity;
    B(int v, int q) : A(v), quantity(q) {}
};

int main() {
    int i = 12;  // an integer
    B b(12, 3);  // an instance of B
    A a1 = b;    // (1) convert B to A, also known as "slicing"
    A a2 = i;    // (2) convert int to A, not known as "slicing"
}

唯一的区别是 (1) 调用 A 的复制构造函数(编译器提供,即使代码没有提供),而 (2) 调用 A 的 int 构造函数。

正如其他人所说,Java 不进行对象切片。如果您提供的代码被转换为 Java,那么就不会发生任何类型的对象切片。 Java变量是引用,而不是对象,所以后置条件a = b只是变量“a”与变量“b”引用相同的对象 - 通过一个引用进行的更改可以通过另一个引用看到,依此类推。他们只是用不同的类型来引用它,这是多态性的一部分。一个典型的类比是,我可能将一个人视为“我的兄弟”[**],而其他人可能将同一个人视为“我的牧师”。相同的对象,不同的接口。

您可以使用指针或引用在 C++ 中获得类似 Java 的效果:

B b(24,7);
A *a3 = &b; // No slicing - a3 is a pointer to the object b
A &a4 = b;  // No slicing - a4 is a reference to (pseudonym for) the object b

[**] 事实上,我的兄弟不是牧师。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对象切片,有优势吗? 的相关文章

  • 对象切片,有优势吗?

    对象切片是指当子类被分配给基类时 对象失去一些属性或功能 就像是 Class A Class B extends A Class SomeClass A a new A B b new B Some where if might happe
  • 在枚举的构造函数中访问其他枚举

    我需要类似下面的东西 enum EE A anything B beta Z zulu ALL EE String s this s s EE String s for EE ee values PROBLEM HERE if ee ALL
  • 如何*真正*编写 UML 基数?

    我想一劳永逸地知道如何编写 UML 基数 因为我经常不得不争论它们 所以非常欢迎证明和来源 如果我想解释一下a Mother可以有几个Children but a Child有且仅有一个Mother 我应该写 Mother 1 Child
  • 为什么要使用继承? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 为什么 Go 中无法将 [Size]byte 转换为字符串?

    我有一个大小字节数组 是我做完之后得到的md5 Sum data byte testing var pass string var b 16 byte b md5 Sum data pass string b 错误 cannot conve
  • 如何在基类中声明类似工厂的方法?

    我正在寻找 C 类设计问题的解决方案 我想要实现的是在基类中拥有静态方法方法 它将返回后代类型对象的实例 关键是 其中一些应该是单身人士 我正在用VCL编写它 所以有可能使用 properties 但我更喜欢纯 C 解决方案 class B
  • 向类添加属性的更 Pythonic 方式?

    我正在使用来自两个不同网页的数据集 但对于同一个人 数据集是合法信息 一些数据在第一页上可用 因此我使用正确的信息初始化被告对象 并将我当前没有数据的属性设置为null 这是班级 class Defendant object holds d
  • 在 C++ 中类继承的情况下强制延迟方法解析

    考虑以下类结构 class foo public int fun cout lt lt in foo lt lt endl class bar class1 public foo public int fun cout lt lt in b
  • 棋子层次结构设计:继承与类型字段

    我有一个片段的基类 class piece 和一个包含派生对象的数组 piece board 8 8 优点 通过虚拟函数进行简洁的设计 缺点是 如果我必须在板上找到一块或比较一块 我必须恢复到动态铸造 或 typeid 它很丑陋 并且在发出
  • 适当使用静态方法

    从概念上讲 当方法仅接受输入并将输入重新格式化为输出时 使用静态方法 C 是否合适 例如 public static string FormatString string inputString return some formatting
  • 添加类方法后如何更新类的实例?

    我发现自己陷入了困境 我开发了一个类 然后创建了该类的一个实例 这些类通常会执行数据和统计操作 这些操作需要很长时间 有时需要 20 分钟 我将继续开发我的类 并向其中添加其他方法 现在 如何使用新方法更新以前的类实例而不重新初始化该类的旧
  • 如何在 Lua 中实现 OO?

    Lua 没有内置对 OO 的支持 但它允许您自己构建它 您能否分享一些实现面向对象的方法 请为每个答案写一个例子 如果您有更多示例 请发布另一个答案 我喜欢将 OOP 视为容器 对象 内的数据封装以及可以使用该数据完成的操作子集 还有很多内
  • 如何使用工厂来创建使用策略模式的对象?

    假设我们的在线商店有一个简单的支付功能 我们希望使用不同的交易处理器来管理不同的交易 交易可以是付款或退款 交易处理器可以是 Paypal 或 Payplug 所以我们有以下课程 class PaymentTransaction imple
  • 如何从对象文字数组中切片数组?

    我有这个数组 其中每个索引都包含一个对象文字 所有对象字面量都具有相同的属性 某些对象文字对于给定属性具有相同的值 我想创建一个包含only那些对象文字 我的想法是对数组进行排序 并将其切片成一个新数组 这是数组 var arr arr 0
  • 现实世界抽象类使用简单示例

    有没有使用抽象类的现实世界简单示例 我试图进入 PHP 的 OOP 但我仍然无法理解 为什么应该使用抽象类以及何时使用 是的 我知道不可能创建抽象类实例 只能创建继承它的类的实例 也许您有一个图像类 并且有 2 个驱动程序 GD 和 Ima
  • 为什么我不能将一个类划分为多个文件

    我正在尝试创建一个类TestClass它分为几个文件 我将它分成 3 个文件 其中第一个文件TestClassPart1 php已经开始上课了class TestClass 和最后一个文件TestClassPart3 php有班级的右括号
  • 预期设备类型为 cuda 的对象,但在 Pytorch 中获得了设备类型 cpu

    我有以下计算损失函数的代码 class MSE loss nn Module metric L1 L2 norms or cosine similarity mode training or evaluation mode def init
  • 如何让枚举存储每个条目的额外信息

    我有一组包含相关信息的项目 这些项目是由我 程序员 定义的 用户不需要更改它们 它们永远不需要根据配置进行更改 并且它们唯一可能更改的时间是在我的应用程序的未来版本中 我事先知道这些项目应该有多少 以及它们的确切数据是什么 枚举是一种很棒的
  • 如何在 PHP 中检查特定类型的对象

    我有一种方法 它接受 PDO 对象作为参数 允许用户使用现有连接 而不是打开新连接的方法 并节省资源 public static function databaseConnect pdo null 我知道is object 检查参数是否是一
  • PHP 特性 - 定义通用常量

    定义可由命名空间内的多个类使用的常量的最佳方法是什么 我试图避免过多的继承 因此扩展基类不是理想的解决方案 并且我正在努力寻找使用特征的良好解决方案 这在 PHP 5 4 中是否可行 或者应该采取不同的方法 我有以下情况 trait Bas

随机推荐

  • 如何在滚动 iPhone 上向 tableview 添加元素?

    我正在使用 UITableView 列出来自 Web 服务的元素 我需要做的是首先从Web服务调用20个元素并显示在列表中 当用户向下滚动时从Web服务调用另外20个记录并添加到表格视图 这个怎么做 您可以从 Web 服务加载 20 个项目
  • 如何防止视图将其模型传递给部分视图,而是传递 null?

    在 ASP NET MVC 和使用 Razor 中 我有一个视图 父视图 调用另一个视图 子视图 作为部分视图 两者都是强类型的 但它们具有不同的模型类型 通常 在这些情况下 我们会显式地将模型从父视图传递到子视图 Html Partial
  • 光标在 Google 地图应用程序中消失

    这确实很奇怪 使用 API v3 创建 Google 地图应用程序后 有时当我将光标悬停在地图上时 鼠标光标会消失 我需要与地图之外的几个控件进行交互 当我点击其中一个并且地图失去焦点后 问题就显现出来了 这事发生在别人身上过吗 我尝试将焦
  • 如何在 Bootstrap 中水平居中表格

    这是我的代码 我想做的是将这张桌子放在容器的中心 但相反 当我使用 容器 类时 它默认向左对齐 并且当我对 div 使用 容器流体类 时 它使用全宽度 我想将桌子水平居中 有人可以帮忙吗 div class container fluid
  • NaN 是假的吗?为什么 NaN === false 返回 false

    Why NaN false gt false NaN 不是假吗 Why NaN NaN gt 错误 但是 NaN NaN gt 正确 我绞尽脑汁想弄清楚这个问题 Falsy并且严格等于false是非常不同的事情 这就是为什么一个人有一个y而
  • 条件“可浏览”属性

    有没有办法使 可浏览 属性成为有条件的 以便应用它的属性有时会出现在属性页中 有时不会出现 谢谢 我不确定这是否适用于您的情况 但您可以通过调用下面的函数在运行时调整 可浏览 装饰
  • Mysql 客户端使用 `docker-compose run` 与 `docker-compose exec` 调用

    为什么调用时需要指定主机docker compose run e g docker compose run db container mysql uuser ppass db name h db container 似乎直接相当于 dock
  • 将 CSV 文件拆分为较小的文件但保留标题?

    我有一个巨大的 CSV 文件 有 100 万行 我想知道是否有一种方法可以将此文件拆分为较小的文件 但保留所有文件的第一行 CSV 标题 它似乎split速度非常快 但也非常有限 您不能向文件名添加后缀 例如 csv split l1100
  • 如何处理 Akka 子 actor 的长时间初始化?

    我有一个演员 它创建一个子演员来执行一些冗长的计算 问题是子 Actor 的初始化需要几秒钟 并且父 Actor 在子 Actor 创建和完全初始化之间发送给子 Actor 的所有消息都将被丢弃 这是我正在使用的代码的逻辑 class Ch
  • TypeScript 类型的并集被解析为类型的交集

    我有这个片段 class J constructor public foo number class B constructor public bar string interface Cache json J binary B funct
  • 如何预填写 Google 表单复选框?

    我看过这个问题 是否可以使用谷歌电子表格中的数据 预填写 谷歌表单 https stackoverflow com questions 20108511 is it possible to prefill a google form usi
  • 将“onclick”应用于 iFrame 中的所有元素

    如何使用 JavaScript DOM 来应用onclick事件到链接内部iframe 这是我正在尝试但不起作用的方法 document getElementById myIframe contentDocument getElements
  • 使用 JOIN(大表性能)Postgresql 进行 UPDATE FROM?

    我试图让以下查询以合理的性能执行 UPDATE order item imprint SET item new id oi item new id FROM order item oi INNER JOIN order item impri
  • 通过 Rails 访问 has_many 上的附加值

    我在访问 has many 上名为 permission 的附加参数的值时遇到了真正的麻烦 这可能是很简单的事情 我的 3 个型号是 class User lt ActiveRecord Base has many players user
  • CultureAndRegionInfoBuilder 不存在

    好吧 这是一个奇怪的事情 我正在尝试使用以下方法创建自定义文化 using System Globalization var x new CultureAndRegionInfoBuilder 但我收到了令人讨厌的红色 Resharper
  • 在 Firebase 项目中集成 Gmail 连接

    我开发了一个应用程序 它使用 gmail api 来获取来自用户的所有邮件 然后我将此应用程序分为一个示例 几乎是空的 和一个执行所有操作的片段 这样我以后就可以轻松地将我的片段集成到我团队的项目设置中 现在我的片段位于另一个项目中 gma
  • 从 Lambda 向 AWS IoT Core 发布 MQTT 消息

    我是 AWS 世界的新手 目前正在开发一项 Alexa 技能 该技能只需向 AWS IoT Core 代理发布一条 mqtt 消息 与之前创建的 事物 和主题进行交互 目前我正在使用 boto3 但我不确定这是正确的路径 这是代码 但在部署
  • 移动 Safari - 视口设备高度未按预期工作

    我有一个网络应用程序 我试图在 iPad 3 上运行 当我拉起它时 该应用程序允许垂直滚动 但实际上不应该 我已经对其他网络应用程序执行了相同的过程 没有任何问题 并且不确定这次我错过了什么 在我的 html 的 head 元素内 我有以下
  • 如何使用 EditTextPreference 作为屏蔽密码文本字段?

    我有一个非常简单的问题 我有一个EditTextPreference我想用它来获取用户的密码 并且我希望它被屏蔽 我怎样才能做到这一点 下面是一个使用 xml 的简短示例
  • 对象切片,有优势吗?

    对象切片是指当子类被分配给基类时 对象失去一些属性或功能 就像是 Class A Class B extends A Class SomeClass A a new A B b new B Some where if might happe