2013-05-19 34 views
7

Tôi đã viết một ví dụ lớp C++ đơn giản với 1 hàm tạo không tham số, 1 hàm tạo param, 2 hàm tạo bản sao, 1 toán tử gán và toán tử 1 cộng.Xác định các nhà xây dựng sao chép nào được gọi trong mã C++

class Complex { 
protected: 
    float real, img; 
public: 
    Complex() : real(0), img(0) { 
     cout << "Default constructor\n"; 
    } 

    Complex (float a, float b) { 
     cout << "Param constructor" << a << " " << b << endl; 
     real = a; 
     img = b; 
    } 

    // 2 copy constructors 
    Complex(const Complex& other) { 
     cout << "1st copy constructor " << other.real << " " << other.img << endl; 
     real = other.real; 
     img = other.img; 
    } 

    Complex(Complex& other) { 
     cout << "2nd copy constructor " << other.real << " " << other.img << endl; 
     real = other.real; 
     img = other.img; 
    } 

    // assignment overloading operator 
    void operator= (const Complex& other) { 
     cout << "assignment operator " << other.real << " " << other.img << endl; 
     real = other.real; 
     img = other.img; 
    } 

    // plus overloading operator 
    Complex operator+ (const Complex& other) { 
     cout << "plus operator " << other.real << " " << other.img << endl; 
     float a = real + other.real; 
     float b = img + other.img; 
     return Complex(a, b); 
    } 

    float getReal() { 
     return real; 
    } 

    float getImg() { 
     return img; 
    } 
}; 

tôi sử dụng lớp này trong chính một cách chính xác như thế này:

int main() { 
    Complex a(1,5); 
    Complex b(5,7); 
    Complex c = a+b; // Statement 1 
    system("pause"); 
    return 0; 
} 

Kết quả được in như:

Param constructor 1 5 
Param constructor 5 7 
plus operator 5 7 
Param constructor 6 12 

Tôi nghĩ rằng một constructor sao chép phải được sử dụng trong Bản Tuyên Bố 1, nhưng tôi không thực sự biết cái nào được gọi. Hãy cho tôi biết cái nào và tại sao? Cảm ơn rất nhiều

+3

Nó có thể được elided. – chris

+0

Nên là phiên bản 'const' của hàm tạo bản sao, bạn luôn có thể đặt các bản in gỡ lỗi trong các phần tử của hàm tạo để tự kiểm tra. – iammilind

+0

@iammilind nếu ctor được elided, các bản in ra được elided quá, được cho phép theo tiêu chuẩn. – Walter

Trả lời

9

Trình biên dịch đang thực hiện cuộc gọi (thực tế, hai cuộc gọi) tới trình tạo bản sao. Điều này được cho phép (nhưng không bắt buộc!) Theo đoạn 12.8/31 của tiêu chuẩn C++ 11 ngay cả khi hàm tạo hoặc hàm hủy có tác dụng phụ:

Khi đáp ứng các tiêu chí nhất định, thực hiện được phép bỏ qua sao chép/di chuyển xây dựng của một đối tượng lớp , ngay cả khi hàm tạo được chọn cho hoạt động sao chép/di chuyển và/hoặc hàm hủy đối tượng có các tác dụng phụ. [..] sự bỏ bớt này hoạt động sao chép/di chuyển, được gọi là bản sao sự bỏ bớt, được cho phép trong các trường hợp sau (mà có thể được kết hợp để loại bỏ nhiều bản sao):

- trong một tuyên bố return trong một hàm với một kiểu trả về lớp, khi biểu thức là tên của một đối tượng tự động không bay hơi (không phải là tham số hàm hoặc tham số bắt buộc) với cùng kiểu cv-unqualified làm kiểu trả về hàm, thao tác sao chép/di chuyển có thể được bỏ qua bằng cách xây dựng đối tượng tự động trực tiếp vào giá trị trả về của hàm

[...]

- khi đối tượng lớp tạm thời không bị ràng buộc với tham chiếu (12.2) sẽ được sao chép/di chuyển đến đối tượng lớp có cùng loại cv-không đủ tiêu chuẩn, thao tác sao chép/di chuyển có thể được bỏ qua bởi xây dựng các đối tượng tạm thời trực tiếp vào mục tiêu của bản sao bỏ qua/di chuyển

Nếu trình biên dịch không bõ mẫu âm chót các cuộc gọi đến constructor sao chép, sau đó là người đầu tiên sẽ được chọn hai lần, tức là một trong những có chữ ký sau:

Complex(const Complex& other) 
.210

Lý do là:

  • Giá trị trả về bởi operator + là sao chép từ một khởi tạm thời (Complex(a, b)), và chỉ có giá trị trái tài liệu tham khảo để const thể liên kết với temporaries.Mọi thứ sẽ khác nếu operator + được viết như sau:

    Complex operator+ (const Complex& other) { 
        // ... 
        Complex c(a, b); 
        return c; 
    } 
    

    Trong trường hợp này, các nhà xây dựng bản sao thứ hai sẽ được gọi là, kể từ c không const -qualified và là một giá trị trái, vì vậy nó có thể được liên kết với một giá trị trái tham chiếu đến không const;

  • Đối tượng c trong main() đang được sao chép từ giá trị rvalue (giá trị trả về operator + cũng là tạm thời). Điều này đúng bất kể cách thức operator + trả về đối tượng Complex của nó, miễn là nó trả về giá trị. Vì vậy, các nhà xây dựng bản sao đầu tiên sẽ được chọn bất cứ khi nào sao chép elision không được thực hiện.

Nếu bạn đang sử dụng GCC và muốn xác minh hành vi này, hãy thử đặt cờ -fno-elide-constructors biên soạn (Clang hỗ trợ nó quá, nhưng phiên bản 3.2 đã có một lỗi và tôi không biết liệu nó đã được cố định).

Các vấn đề liên quan