传递继承引用类型时切片或不切片

Posted

技术标签:

【中文标题】传递继承引用类型时切片或不切片【英文标题】: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, 或者从继承引用对象中获取值, 通过传递,将它们切片。

注意事项:

在写这个问题的过程中没有割骆驼! 相关的,更一般的处理:Where should I prefer pass-by-reference or pass-by-value?

【问题讨论】:

为什么不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:见编辑。 【参考方案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 的函数,天真而直接。

【讨论】:

以上是关于传递继承引用类型时切片或不切片的主要内容,如果未能解决你的问题,请参考以下文章

Golang 函数传参使用切片而不使用数组为什么?

Go切片数组深度解析

关于切片参数传递的问题

Go语言之GO 语言引用类型

Go语言引用类型

24_切片的使用