2011-01-31 121 views
3

我得到一个编译错误与下面的代码:C++默认构造

main.cpp: In function âint main()â: 
main.cpp:38: error: no matching function for call to âComplex::Complex(Complex)â 
main.cpp:22: note: candidates are: Complex::Complex(Complex&) 
main.cpp:15: note:     Complex::Complex(double, double) 

但是,当我改变参数类型的拷贝构造函数为const复杂&,它的工作原理。 我在想,将使用2 Complex :: Complex(2.0,0.0)调用默认构造函数,然后调用复制构造函数以创建具有Complex(2.0。0)副本的副本。这不正确吗?

#include <iostream> 
using namespace std; 

class Complex { 
     double re; 
     double im; 

public: 
     Complex(double re=0, double im=0); 
     Complex(Complex& c); 
     ~Complex() {}; 
     void print(); 
}; 

Complex::Complex(double re, double im) 
{ 
     cout << "Constructor called with " << re << " " << im << endl; 
     this->re = re; 
     this->im = im; 
} 

Complex::Complex(Complex &c) 
{ 
     cout << "Copy constructor called " << endl; 
     re = c.re; 
     im = c.im; 
} 


void Complex::print() 
{ 
     cout << "real = " << re << endl; 
     cout << "imaginary = " << im << endl; 
} 

int main() 
{ 
     Complex a = 2; 
     a.print(); 
     Complex b = a; 
     b.print(); 
} 
+0

你怎么调用构造函数? – Argote 2011-01-31 21:29:18

+0

如果它和`const`一起工作,那么你为什么不坚持? – 2011-01-31 21:29:54

+1

Microsoft的编译器不报告这些错误。它按照您的预期执行,即。它将Complex a = 2视为Complex a(2,0)。其他编译器可以将其视为Complex a = temp,其中temp是初始化的。在这种情况下,复制构造函数成为问题。 const修饰符的缺失意味着temp的只读属性不能保证。 – 2011-01-31 21:44:41

回答

1

在C复制构造++需要论证的const部分,以便采取一个const参数,因为你发现了。否则,你并没有创建一个可以接受const参数的拷贝构造函数,而是创建了一个拷贝构造函数,该构造函数将一个非const Complex&作为参数。

+0

T类的构造函数确实是一个拷贝构造函数。 – 2011-01-31 21:31:16

1

您总是使用&创建一个复制构造,因此您不必复制整个对象以供函数使用它。创建对象副本需要时间,引用它效率更高。

在任何情况下,都需要将您的对象参数放在const之前,这样复制构造函数才能保证而不是可以更改输入对象。例如:

Complex::Complex(const Complex &c) 
{ 
     cout << "Copy constructor called " << endl; 
     re = c.re; 
     im = c.im; 
     c.im = 'something'; // This would not work 
} 

问候,
丹尼斯M.

1

这段代码的问题是,你的拷贝构造函数与此签名定义:

Complex::Complex(Complex &c) 

这需要一个非const参考作为参数,这可能不是你想要的。这意味着,例如,如果您尝试使用复制构造函数复制Complex对象,则可以修改原始对象!

为了解决这个问题,改变你的代码采取Complex通过const参考:

Complex::Complex(const Complex &c) 

更一般地说,拷贝构造函数和赋值运算符应始终把他们的争论中通过const引用,除非你有一个非常强有力的理由以其他方式思考。

我应该指出你的代码中还有其他一些东西。对于初学者来说,在这种情况下,您的复制构造函数不是必需的,因为它只是对所有字段进行直接复制。有一条经验法则叫做“三条规则”,说如果你有一个析构函数,那么你应该只有一个拷贝构造函数(然后你还应该有一个赋值操作符)。否则,编译器提供的默认函数可能足以满足您的要求。

此外,没有理由写自己的Complex类,除非你绝对必须。 <complex>标题将complex<T>定义为库类。

9

当你写

Complex a = 2; 

编译器将不直接调用使用0作为默认参数来构建aComplex构造,而是会考虑是否可以“转换” 2为Complex

做转换您会发现您Complex(re,im)版本,可以用它得益于默认值,这样的事实:你没有宣布你的构造explicit,但随后必须找到一种方式转让该值来a

此“传输”工具可能是复制构造函数。然而,可以使用Complex(re,im)构建的复杂值是临时,并且对于C++中的一些可疑原因,您不允许将临时作为非const引用传递给函数。

所以你的拷贝构造函数不能与临时使用,因为没有办法使用2

如果你宣布你的拷贝构造函数,而不是接受一个const参考,则暂时可以初始化a编译器被套牢传递给你的拷贝构造函数来初始化a,所以一切都如你所愿。

可以使用语法Complex a(2)直接初始化a,在这种情况下,不需要使用复制构造函数。

还要注意的是奇怪,可能是当您使用语法Complex a = ...编译器必须检查它是否是合法使用拷贝构造函数,但一旦合法性已经检查了它允许不调用它,使用直接初始化代替。换句话说,即使您需要声明接受const引用的拷贝构造函数仍然可以编译,编译器实际上可以跳过该部分并直接构建a而不调用拷贝构造函数(即使拷贝构造函数 - 与您的情况一样 - 有副作用)。这个显然疯狂的规则已被添加到能够在生成的代码中进行一些优化。