对象切片,有优势吗?

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(使用前将#替换为@)

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

  • 无法在类对象的 ArrayList 中存储值。 (代码已编辑)

    这基本上是一个 Java 代码转换器 它涉及一个 GUI 让用户输入类类型 名称和方法 为了存储值 我创建了一个类VirtualClass与ArrayList
  • 如何决定使用 IS A 还是 HAS A Relation

    public class B public String getMe return Some 假设我有一个上面的类 我们应该通过哪些参数来决定使用什么 是否是一个或有一个关系 HAS A public class A public stat
  • 使用超类初始化器初始化类

    我有两个类 一个是另一个的子类 比如说Animal and Dog 超类有一些初始化器 比如initAnimal 子类有一些初始化器 比如initDog 问题是 从编译器的角度来看 做类似的事情是完全合法的Dog adog Dog allo
  • 切片 Dataframe 时出现 KeyError

    我的代码如下所示 d pd read csv Collector Output csv df pd DataFrame data d dfa df copy dfa dfa rename columns OBJECTID Object ID
  • 如何考虑子类型的多态性

    里氏替换原则指出 超类型的不变量必须保留在子类型中 我对这个原理和多态性的交叉特别感兴趣 事实上 特别是子类型多态性 参数多态性和 Haskell 类型类似乎就是这种情况 因此 我知道当函数的参数是逆变且返回类型是协变时 函数是子类型 我们
  • 抽象类和接口之间的区别[重复]

    这个问题在这里已经有答案了 可能的重复 接口与基类 https stackoverflow com questions 56867 interface vs base class 我不明白抽象类和接口之间的区别 我什么时候需要使用哪种字体
  • 用 C# 编写的带有点击移动的 WPF 游戏

    我试图将标签网格移动到鼠标的位置 就像冒险游戏中的移动一样 理想情况下 我会在途中删除并重新绘制它们 但是 现在我只想弄清楚如何将 int 转换为厚度或 pointtoscreen 到目前为止我有 player XMove int Mous
  • Python 切片对象和 __getitem__

    python 中是否有内部的东西来处理传递给的参数 getitem 不同 并自动转换start stop step构造成切片 这是我的意思的演示 class ExampleClass object def getitem self args
  • 如何在我的 HttpClient 执行器中遵循单一职责原则?

    我在用RestTemplate http docs spring io spring docs current javadoc api org springframework web client RestTemplate html as
  • 从关系数据库中“区分”对象

    我们的 win32 应用程序根据 MySQL 关系数据库中多个表中的数据组装对象 对于这样的对象 多个修订版本存储在数据库中 当存储某些内容的多个修订版本时 迟早您会问自己这样的问题 您是否可以想象两个修订版本之间的差异 所以我的问题是 比
  • 拦截对对象属性的 __getitem__ 调用

    问题 我怎样才能拦截 getitem 调用对象属性 解释 所以 场景如下 我有一个对象将类似字典的对象存储为属性 每次 getitem 该属性的方法被调用 我想拦截该调用并根据键对获取的项目进行一些特殊处理 我想要的看起来像这样 class
  • 创建新类别的优点和缺点是什么? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 这可能是一个非常基本的问题 但这是我在学习更多有关 Actionscript 3 的过程中实际遇到的问题 然而 我的第一个问题非常笼统 什么时候
  • 如何访问带有美元符号的 PHP 对象属性?

    我有一个 PHP 对象 其属性中有一个美元 符号 如何访问该属性的内容 例子 echo object gt variable Ok echo object gt variable WithDollar Syntax error With 变
  • 动态重新定义 PHP 类函数?

    我试图弄清楚如何动态导入大量 PHP 类函数 例如 class Entity public function construct type require once type functions php person new Entity
  • 为什么/何时应该使用泛型方法?

    学习Java的时候遇到过通用方法 public
  • 使用继承编写 __repr__ 函数的正确方法

    我正在尝试 OOP python 但我不确定 repr 函数继承 由于父类函数如下所示 def repr self Returns representation of the object return r format Class nam
  • PHP:我是否将事件驱动编程与信号感知接口(信号和槽/观察者模式)混淆了?

    我看到很多人说 Symfony2 Zend Framework 2 等都是事件驱动的 在桌面世界中 通过事件驱动编程 我了解到应用程序每当其状态发生变化时都会通知其观察者 由于 PHP 应用程序是无状态的 因此无法执行此类操作 IE 让观察
  • 阶级等级制度中频繁的贬低总是邪恶的吗?

    据我所知 如果在类层次结构中频繁使用向下转型是没有好处的 我同意这一点 但是这条规则有哪些例外情况 如果有的话 这就是我的图形编辑器设计的薄弱之处 我有两个层次结构 其中几何图形层次结构与图形基元分离 像这样 public class Ge
  • 如何正确使用状态模式?

    在我的编程经验中 我遇到过一些状态模式的实现 并且完成了一些 我见过它们在各种场景中使用 主要是 UI 和解析 问题在于 所有这些在快速开发的压力下都变成了难以维护和理解的代码块 我正在考虑重构其中之一 但我无法在网上找到合适的资源 网上有
  • 将同一 numpy 数组的两个视图组合成单个视图而不复制数组?

    我有一个大型 2d numpy 数组 我想删除它的子集并处理函数剩下的内容 我需要对许多子集执行此操作 因此理想情况下我不想每次都创建数组的副本 该函数不会更改数组中的任何值 mat np load filename mat 1 mat i

随机推荐

  • 如何在滚动 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