【问题标题】:To slice or not to slice when passing inheriting reference types传递继承引用类型时切片或不切片
【发布时间】:2022-01-20 11:48:21
【问题描述】:

我正在编写一些涉及“现实生活”而不是纯程序实体的代码。假设它是一个骆驼处理库。现在,我的图书馆有两个骆驼reference-type 类:CamelSingingCamelCamel 是一个没有虚拟成员的具体类; SingingCamel : public Camel { } 是一只可以唱歌的骆驼,而且在编程方面,没有覆盖/阴影。像对待不唱歌的骆驼一样对待唱歌的骆驼是没有问题的。

现在,由于它们都是引用类型而不是值类型类,我宁愿按值传递它们。不幸的是,如果我写:

void have_joyride(Camel camel, Person person)

(请记住 - 这些是 reference 类;这不会创建新骆驼或新人)

...然后我正在切割我的SingingCamel

C++ 核心指南say:

ES.63:不要切片

切片 - 即使用赋值或初始化仅复制对象的一部分 - 最常导致错误,因为该对象应被视为一个整体。在极少数情况下故意切片的代码可能会令人惊讶。

现在,并不是我不能避免切片。我当然可以写:

void have_joyride(Camel const &  camel, Person const &  person);

这样就可以了。 ...除了,在这种情况下,我实际上需要有 四个 功能:

void have_joyride(Camel const &  camel, Person const &  person);
void have_joyride(Camel const &  camel, Person       && person);
void have_joyride(Camel       && camel, Person const &  person);
void have_joyride(Camel       && camel, Person       && person);

这违反了another C++ 核心准则:

ES.3:不要重复自己,避免冗余代码

重复或以其他方式冗余的代码会掩盖意图、使逻辑更难理解、更难维护等问题。它通常源于剪切和粘贴编程。

还有this one:

F.16:对于“in”参数,通过值传递廉价复制的类型,通过引用 const 传递其他类型

两者都让调用者知道函数不会修改参数,并且都允许通过右值进行初始化。


所以我问自己:

切还是不切,这是个问题:
受苦是否更崇高
令人发指的重载的 lrefs 和 rrefs,
或者从继承引用对象中获取值,
通过传递,将它们切片。

注意事项:

【问题讨论】:

  • 为什么不template <typename Camel, typename Rider> void have_joyride(Camel camel, Rider person);template <typename Camel, typename Rider> void have_joyride(Camel&& camel, Rider&& person);
  • @NathanOliver: 1. 因为它是一个混淆,这也表明其他类可能被传递到have_joyride()。如果我想限制它,我需要写一个需求,或者用 SFINAE 让它变得更丑,或者引入一个概念并依赖于 C++20。 2. 因为 F.16。 ...不过,这可能是一个答案。
  • 为什么需要这些重载?
  • “参考类”到底是什么意思?
  • @NathanPierson:见编辑。

标签: c++ pass-by-reference pass-by-value object-slicing


【解决方案1】:

这是 C++ 核心指南 say 你可以做的:

另类

如果您要切片,请定义一个显式操作来执行此操作。这样可以避免读者混淆。

并改编他们的例子,我会得到:

class SingingCamel : public Camel {
    public:
    Camel as_camel();
    // ...
};

SingingCamel sc { /* ... */ };
Camel c1 {sc};  // ideally prevented by the definition of Camel
Camel c2 {sc.as_camel()};

但坦率地说,我不太喜欢这种解决方案。我想将我的SingingCamel 传递给接受Camels 的函数,天真而直接。

【讨论】:

    猜你喜欢
    • 2020-04-06
    • 2013-09-14
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 2016-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多