2013-05-24 35 views
5

i am new to C++ programming, khi tôi đang thực hiện một số chương trình C++ tôi đã nghi ngờ đó là lý do tại sao copy constructor được gọi khi tôi vượt qua một đối tượng làm đối số theo giá trị cho hàm. xin vui lòng xem mã dưới đây của tôi trong đó tôi đang đi qua một đối tượng của lớp như là một đối số theo giá trị cho một hàm display() nhưng nó gọi là constructor sao chép và sau đó điều khiển là nhấn display() chức năng nhưng tôi hiểu tại sao nó như vậy xin vui lòng giúp đỡ.lý do tại sao sao chép constructor gọi khi chúng ta truyền đối tượng như một đối số theo giá trị cho một phương thức

#include "stdafx.h" 
#include <iostream> 
using namespace std; 

class ClassA 
{ 
    private: 
     int a, b; 
    public: 
     ClassA() 
     { 
      a = 10, b = 20; 
     } 
     ClassA(ClassA &obj) 
     { 
      cout << "copy constructor called" << endl; 
      a = obj.a; 
      b = obj.b; 
     } 
}; 
void display(ClassA obj) 
{ 
    cout << "Hello World" << endl; 
} 
int main() 
{ 
    ClassA obj; 
    display(obj); 
    return 0; 
} 

Trả lời

6

Để xây dựng hai câu trả lời đã được đưa ra một chút:

Khi bạn xác định các biến là "giống như" một số biến khác, bạn có về cơ bản hai khả năng:

ClassA aCopy = someOtherA; //copy 
ClassA& aRef = someOtherA; //reference 

Thay vì phi Tham chiếu const lvalue có tất cả tham chiếu const và tham chiếu rvalue. Điều chính tôi muốn chỉ ra ở đây là, aCopy độc lập với someOtherA, trong khi aRef thực tế là cùng một biến như someOtherA, nó chỉ là một tên (bí danh) cho nó.

Với thông số chức năng, về cơ bản thì giống nhau. Khi tham số là một tham chiếu, nó sẽ bị ràng buộc với đối số khi hàm được gọi, và nó chỉ là một bí danh cho đối số đó. Điều đó có nghĩa, những gì bạn làm với các thông số, bạn làm gì với lập luận:

void f(int& iRef) { 
    ++iRef; 
} 

int main() { 
    int i = 5; 
    f(i); //i becomes 6, because iRef IS i 
} 

Khi tham số là một giá trị, nó chỉ là một bản sao của các đối số, vì vậy bất kể những gì bạn làm để tham số, tham số vẫn không thay đổi.

void f(int iCopy) { 
    ++iCopy; 
} 

int main() { 
    int i = 5; 
    f(i); //i remains 5, because iCopy IS NOT i 
} 

Khi bạn chuyển giá trị, tham số là đối tượng mới. Nó phải như vậy, vì nó không giống như đối số, nó độc lập. Tạo một đối tượng mới là một bản sao của đối số, có nghĩa là gọi hàm tạo bản sao hoặc di chuyển hàm tạo, tùy thuộc vào thời gian đối số là một giá trị hoặc rvalue. Trong trường hợp của bạn, làm cho hàm truyền theo giá trị là không cần thiết, bởi vì bạn chỉ đọc đối số.

Có một Hướng dẫn từ GotW #4:

thích đi qua một tham số chỉ đọc bằng const & nếu bạn chỉ đi để đọc từ nó (không phải tạo một bản sao của nó).

4

Bởi vì đi ngang qua giá trị cho một hàm nghĩa hàm có bản sao riêng của mình của đối tượng. Để kết thúc này, các nhà xây dựng bản sao được gọi.

void display(ClassA obj) 
{ 
    // display has its own ClassA object, a copy of the input 
    cout << "Hello World" << endl; 
} 

Lưu ý rằng trong một số trường hợp, bản sao có thể được ưu tiên, nếu giá trị tạm thời được chuyển cho hàm.

2

Như juanchopanza đã nói :, bạn vượt qua theo giá trị, điều này gây ra một bản sao. Nếu bạn muốn ngăn chặn điều này, bạn có thể vượt qua bằng cách tham khảo:

void display(const ClassA &obj) 

Trên một sidenote: Bạn nên khai báo sao chép ctor của bạn để có những lập luận như tham chiếu const:

ClassA(const ClassA &obj) 

Nếu không, bạn sẽ không có thể sử dụng ctor sao chép trên các đối tượng được đặt tên được đánh dấu là const hoặc với các thời gian. Nó cũng ngăn cản bạn vô tình thay đổi đối tượng được truyền trong đối tượng.