为什么void setOutputFormat(ostream out,int decimal_places)会导致错误?

时间:2010-09-25 21:49:58

标签: c++

如果我将其更改为void setOutputFormat(ostream& out,int decimal_places), 通过引用打电话,它的工作原理。我不明白为什么呢? 结构和类之间有什么区别,除了struct成员默认是public,而类成员默认是私有的?

3 个答案:

答案 0 :(得分:3)

你是对的,除了默认的私有vs私有之外,class和struct之间没有区别。

这里的问题是ostream没有复制构造函数,所以你不能按值传递它。

答案 1 :(得分:2)

当您尝试通过传递ostream时,您尝试制作流的副本,这是无效的,因为流对象是< em> noncopyable ,也就是说,它们没有定义复制构造函数。但是,当您通过 reference 传递流时,该函数会向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就地修改原始流。希望这能在某种程度上澄清这个问题。

答案 2 :(得分:0)

正如其他人所说,您正在尝试创建不可复制对象(流)的副本,从而导致该错误。

在C ++中,当你将var作为参数传递时,你会复制它(与C#相反,对于引用类型,你总是隐式地传递对它的引用)。

默认情况下,C ++为每个类提供了一个按位复制构造函数,但通常不是所需的:例如,想想拥有资源句柄的类:如果你完美克隆了该类型的对象,会有两个人认为拥有这样的资源,他们都会试图在破坏时将其摧毁,这显然不是很好。

因此,C ++允许您为每个类提供复制构造函数,当需要创建对象的副本时调用它。因为对于许多对象(包括流),不需要创建副本(因为它没有意义,因为它不方便或因为麻烦不值得工作),通常复制构造函数被禁用(通过将其标记为{{1或private),您无法创建此类对象的副本。

此外,一般情况下,您必须注意使用属于复杂类层次结构的对象的赋值和副本,因为您可能会遇到对象切片和其他细微问题。实际上,通常的做法是在要作为基类的类中阻止复制和赋值。

在大多数情况下(包括你的),解决方案是通过引用传递这些对象,从而避免复制;请参阅 @Jh Purdy 的答案。

顺便说一句,即使对于可复制对象(例如protected s),最好只传递引用,以避免与复制相关的所有工作;如果您只是为了提高效率而传递引用,但是您不希望修改对象,那么最佳解决方案通常是std::string引用。

拷贝也用在C ++的其他地方;我建议你看一下关于复制构造函数的wikipedia page,以便更好地了解正在发生的事情,但总而言之,要抓住一本C ++书并阅读它:C#在很多方面与C ++不同,并且有许多虚假的相似之处可能让你感到困惑。