传递继承引用类型时切片或不切片
Posted
技术标签:
【中文标题】传递继承引用类型时切片或不切片【英文标题】:To slice or not to slice when passing inheriting reference types 【发布时间】: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:见编辑。
【参考方案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
传递给接受Camel
s 的函数,天真而直接。
【讨论】:
以上是关于传递继承引用类型时切片或不切片的主要内容,如果未能解决你的问题,请参考以下文章