【发布时间】:2011-04-17 06:42:45
【问题描述】:
如果我将其更改为 void setOutputFormat(ostream& out, int decimal_places), 通过引用调用,它可以工作。我不明白为什么? struct和class有什么区别,除了struct成员默认public,class成员默认private?
【问题讨论】:
标签: c++
如果我将其更改为 void setOutputFormat(ostream& out, int decimal_places), 通过引用调用,它可以工作。我不明白为什么? struct和class有什么区别,除了struct成员默认public,class成员默认private?
【问题讨论】:
标签: c++
你说得对,类和结构没有区别,除了默认的私有与私有。
这里的问题是ostream没有拷贝构造函数,所以不能传值。
【讨论】:
当您尝试通过 value 传递 ostream 时,您尝试制作流的 副本,这是无效的,因为流对象是 不可复制,也就是说,它们没有定义复制构造函数。但是,当您通过 reference 传递流时,该函数会收到一个可修改的 alias 到 ostream 实例。举个例子:
void increment(int n) {
// Increment local copy of value.
++n;
}
int x = 5;
increment(x);
// x is still 5.
对比:
void increment(int& n) {
// Increment value itself.
++n;
}
int x = 5;
increment(x);
// x is now 6.
所以通过引用传递流是唯一有意义的方法,因为您希望setOutputFormat 就地修改原始流。希望这能在一定程度上澄清这个问题。
【讨论】:
正如其他人所说,您正在尝试创建不可复制对象(流)的副本,这会导致该错误。
在 C++ 中,当您将 var 作为参数传递时,您会复制它(与 C# 相反,在 C# 中,对于引用类型,您总是隐式传递对它的引用)。
默认情况下,C++ 为每个类提供了一个按位复制构造函数,但这通常不是必需的:例如,考虑一个拥有资源句柄的类:如果你完美地克隆了该类型的对象,你' 将有两个类认为拥有这样的资源,并且两者都会试图在他们破坏时破坏它,这显然不是很好。
因此,C++ 允许您为每个类提供一个复制构造函数,当必须创建对象的副本时调用该构造函数。由于许多对象(包括流)不需要创建副本(因为它没有意义,因为它不方便或者因为麻烦不值得工作)通常禁用复制构造函数(通过将其标记为private或protected),并且您不能创建此类对象的副本。
此外,一般来说,您必须小心对属于复杂类层次结构的对象进行赋值和按值复制,因为您可能会遇到对象切片和其他微妙的问题。实际上,在作为基类的类中阻止复制和赋值是很常见的做法。
在大多数情况下(包括您的),解决方案是通过引用传递此类对象,从而完全避免复制;请参阅 @Jon Purdy 的答案作为示例。
顺便说一句,即使是可复制的对象(例如std::strings),最好只传递引用,以避免与复制相关的所有工作;如果您只是为了提高效率而传递引用,但又不想修改对象,最好的解决方案通常是 const 引用。
C++ 的其他一些地方也使用了副本;我建议你看看 wikipedia page 关于复制构造函数,以更好地理解发生了什么,但是,总的来说,拿起一本 C++ 书并阅读它:C# 在很多方面都与 C++ 不同,并且有有许多虚假的相似之处可能会让您感到困惑。
【讨论】: