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



我正在编写一些涉及"现实生活中的";与仅编程实体相反。假设这是一个骆驼式图书馆。现在,我的库有两个骆驼引用类型类:CamelSingingCamelCamel是一个没有虚拟成员的具体类;SingingCamel : public Camel { }是一只会唱歌的骆驼,在编程方面没有覆盖/阴影。像对待不唱歌的骆驼一样对待会唱歌的骆驼是没有问题的。

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

void have_joyride(Camel camel, Person person)

(请记住,这些是参考类;这不会创建新的骆驼或新人(

那么我正在切割我的SingingCamel

C++核心指南说:

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);

这违反了C++的另一个核心准则:

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

重复或冗余的代码会模糊意图,使其更难理解逻辑,并使维护更困难,以及其他问题。它通常源于剪切粘贴编程。

以及这个:

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

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


所以我问自己:

切片还是不切片,这就是问题所在:
承受令人愤慨的重载的lref和rrefs,
还是从继承引用对象中获取值,<br]通过传递,切片它们,在头脑中是否更高尚。>

注:

  • 在写这个问题的过程中没有骆驼被切开
  • 相关的、更一般的处理:我应该在哪里更喜欢通过引用传递或通过值传递

这就是C++核心指南所说的你可以做的:

替代

如果你想切片,定义一个显式的操作来实现。这可以避免读者的困惑。

然后调整他们的例子,我会得到:

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的函数。

最新更新