【发布时间】:2022-01-20 11:48:21
【问题描述】:
我正在编写一些涉及“现实生活”而不是纯程序实体的代码。假设它是一个骆驼处理库。现在,我的图书馆有两个骆驼reference-type 类:Camel 和SingingCamel。 Camel 是一个没有虚拟成员的具体类; 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:见编辑。
标签: c++ pass-by-reference pass-by-value object-slicing