我正在编写一些涉及"现实生活中的";与仅编程实体相反。假设这是一个骆驼式图书馆。现在,我的库有两个骆驼引用类型类:Camel
和SingingCamel
。Camel
是一个没有虚拟成员的具体类;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
传递给占用Camel
s的函数。