c++ - 为什么显式定义拷贝构造函数后就无法通过编译了?
PHP中文网
PHP中文网 2017-04-17 14:59:27
0
4
701

初学C++,遇到了这样一个问题,代码如下:

#include <iostream>
using namespace std;

class Complex {
float real, imag;
public:
    Complex(float r = 0.0, float i = 0.0):real(r), imag(i) {
        cout << "Complex constructor called" << endl;
    }
    Complex (Complex& complex):real(complex.real), imag(complex.imag) {
        cout << "Complex copy constructor called" << endl;
    }

 int main() {
    Complex c3 = 3.14;
}

运行的时候会有编译错误,如下:

foobar.cpp:42:13: error: no viable constructor copying variable of
      type 'Complex'
    Complex c3 = 3.14;
            ^    ~~~~
foobar.cpp:10:5: note: candidate constructor not viable: expects an
      l-value for 1st argument
    Complex (Complex& complex):real(complex.real), imag(comp...
    ^

然而,当我删掉我显式定义的拷贝构造函数后,就可以正常编译了,即:

#include <iostream>
    using namespace std;
    
    class Complex {
    float real, imag;
    public:
        Complex(float r = 0.0, float i = 0.0):real(r), imag(i) {
            cout << "Complex constructor called" << endl;
        }
        

     int main() {
        Complex c3 = 3.14;
    }

这样就可以正常编译,请问这是为什么呢?
我用的是 g++ 4.2.1

目前我知道的是:当执行"Complex c3 = 3.14"时发生这些:先调用我显式定义的默认构造函数"Complex(float r = 3.14, float i = 0.0)"创建了一个临时对象,然后利用拷贝构造函数(如果有合法的)去创建c3,然后讲临时对象析构。

其实我的问题有两个:
1)为什么默认的拷贝构函数造能通过编译
2)为什么我定义的拷贝构函数造不能通过编译

补充:之前的问题已解决,但是现在遇到了新的问题
代码如下:

#include <iostream>
using namespace std;

class Complex {
    float real, imag;
public:
    Complex(float r = 0.0, float i = 0.0):real(r), imag(i) {
        cout << "Complex constructor called" << endl;
    }
    Complex(const Complex& complex):real(complex.real), imag(complex.imag) {
        cout << "Complex copy constructor called" << endl;
    }
};

int main() {
    Complex c = 3.22;
}

可以通过编译,但是输出结果为:

Complex constructor called   

并没有调用拷贝构造函数啊,为什么呢?是被编译器优化了吗?
如果不需要调用拷贝构造函数,那为什么之前不加const限定的拷贝构造函数不能通过编译呢?
我用的编译器是 g++ 4.2.1

PHP中文网
PHP中文网

认证高级PHP讲师

모든 응답(4)
PHPzhong

C 사양에서는 컴파일러가 이때 불필요한 복사 생성을 최적화할 수 있기 때문입니다.
GCC와 매개변수 -fno-elide-constructors는 최적화할 필요가 없습니다.
카피 구성 호출 프로세스는 나중에 최적화되었지만. 하지만 구문을 컴파일하고 확인할 때는 여전히 존재해야 합니다. VC는 직접 최적화되며 복사 생성자를 전혀 호출하지 않습니다.
최적화 후 초기화 표현식 Complex c3 = 3.14;는 Complex c3(3.14);과 동일합니다.

Peter_Zhu

Complex c3=3.14;이 복사 생성자는 상수
이므로 정의를 Complex (const Complex& complex);으로 변경해야 합니다.
const 키워드를 추가한 후 const가 아닌 변수도 복사 생성할 수 있으므로 일반 복사는 생성자 모두 const를 추가합니다.
도움이 되었기를 바랍니다!


죄송해요!
에 대한 내 이전 대답은 틀렸습니다. Complex c3=3.14; 이 3.14는 복잡한 객체가 아니기 때문에 시스템은 이를 부동 소수점 유형 객체로 처리해야 하므로 해당 호출은
Complex c3(3.14);
정의한 생성자 가 호출되는데, 이 과정이 초기화이고, 기본 복사 생성자는 호출되지 않습니다.

복사 생성자는 동일한 클래스의 객체가 복사될 때, 즉 Complex 객체가 복사될 때 호출됩니다.

예:
그때에만 Complex c4=c3; 복사 생성자 를 호출합니다.

이전 코드를 내 컴퓨터에서 실행했을 때 컴파일 오류를 발견하지 못했기 때문에 컴파일러 때문인 것 같습니다. 이 부분에 대해 잘 알지 못해서 답변해 드릴 수 없습니다.

제 답변이 도움이 되었으면 좋겠습니다!

小葫芦

클래스에 복사 생성자가 제공되면 기본 매개변수 없는 생성자와 매개변수화된 기본 생성자는 더 이상 제공되지 않으므로 복사 생성자를 삭제하면 정상적인 컴파일이 가능합니다

迷茫

코드를 게시할 때 중괄호와 세미콜론을 잊어버리면 클랭 버그입니다...

Visual C 14.0(VS2015)으로 컴파일 가능합니다.

으아악

실행 결과:

으아악

그리고 추가하신 질문에 대해:

으아악

이것이 하는 일은 실제로 할당이 아니라 초기화입니다. C 의 아버지인 Bjarne Stroustrup이 A Tour of C 에서 설명했습니다.

C 는 위에 사용된 =와 중괄호로 구분된 초기화 목록을 기반으로 하는 범용 형식과 같이 초기화를 표현하기 위한 다양한 표기법을 제공합니다.

으아악 으아악

= 형식은 전통적이며 C로 거슬러 올라갑니다. 하지만 의심스러우면 일반적인 {} 목록 형식을 사용하세요.

최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿