Sự khác biệt giữa toán tử gán và hàm tạo bản sao là gì?


105

Tôi không hiểu sự khác biệt giữa phương thức tạo gán và phương thức tạo bản sao trong C ++. Nó là như thế này:

class A {
public:
    A() {
        cout << "A::A()" << endl;
    }
};

// The copy constructor
A a = b;

// The assignment constructor
A c;
c = a;

// Is it right?

Tôi muốn biết cách cấp phát bộ nhớ của hàm tạo gán và hàm tạo sao chép?


2
Bạn có một cuốn sách C ++ hay không?
sbi

Câu trả lời:


160

Một hàm tạo sao chép được sử dụng để khởi tạo một đối tượng chưa được khởi tạo trước đó từ dữ liệu của một số đối tượng khác.

A(const A& rhs) : data_(rhs.data_) {}

Ví dụ:

A aa;
A a = aa;  //copy constructor

Một toán tử gán được sử dụng để thay thế các dữ liệu của một khởi tạo trước đó đối tượng với dữ liệu số khác của đối tượng.

A& operator=(const A& rhs) {data_ = rhs.data_; return *this;}

Ví dụ:

A aa;
A a;
a = aa;  // assignment operator

Bạn có thể thay thế cấu trúc sao chép bằng cấu trúc mặc định cộng với gán, nhưng điều đó sẽ kém hiệu quả hơn.

(Lưu ý thêm: Các triển khai của tôi ở trên chính xác là những triển khai mà trình biên dịch cấp miễn phí cho bạn, vì vậy sẽ không có ý nghĩa gì nếu bạn triển khai chúng theo cách thủ công. Nếu bạn có một trong hai cách này, có khả năng bạn đang quản lý thủ công một số tài nguyên. Trong trường hợp đó, theo Quy tắc số ba , rất có thể bạn cũng sẽ cần cái còn lại cộng với bộ hủy.)


4
Chỉ cần lưu ý: Ngày nay (C ++ 11 trở đi), chúng có thể được mặc định rõ ràng với =default;.
Deduplicator vào

2
@Deduplicator Cũng cần lưu ý rằng, khi tuân thủ các phân loại yêu cầu các hàm tạo tầm thường, bạn phải phân loại = defaultchúng khi cần có ctor mặc định: chỉ cần thực hiện một phần thân trống bởi chính chúng ta vẫn được coi là ctor do người dùng xác định và do đó (ở cấp Standardese ) không phải là tầm thường và loại bỏ loại khỏi các phân loại yêu cầu một ctor tầm thường.
underscore_d

@sbi Tôi có thể nói rằng trong trường hợp không sử dụng hàm tạo bản sao và thay vào đó là toán tử gán, đối tượng được tạo trước tiên bằng cách gọi hàm tạo có đối số hoặc không có đối số, sau đó toán tử gán được sử dụng và các giá trị mới được gán dựa trên RHS. Trong trường hợp sử dụng phương thức khởi tạo sao chép, phương thức khởi tạo vẫn tương tự sẽ được gọi, nhưng các giá trị được sử dụng để khởi tạo là từ đối tượng khác.
Rajesh

@Rajesh: Tôi bối rối về những gì bạn đang hỏi, và cảm giác của tôi là vì bạn cũng đang bối rối. :)Bạn sẽ thử lại để giải thích những gì bạn đang nói?
sbi 17/03/18

1
@ CătălinaSîrbu: Bạn có thể. Chúng là hai chức năng độc lập.
sbi

41

Sự khác biệt giữa hàm tạo bản sao và toán tử gán gây ra nhiều nhầm lẫn cho các lập trình viên mới, nhưng nó thực sự không quá khó. Tổng kết:

  • Nếu một đối tượng mới phải được tạo trước khi quá trình sao chép có thể xảy ra, thì hàm tạo bản sao sẽ được sử dụng.
  • Nếu một đối tượng mới không phải được tạo trước khi sao chép có thể xảy ra, thì toán tử gán sẽ được sử dụng.

Ví dụ cho toán tử gán:

Base obj1(5); //calls Base class constructor
Base obj2; //calls Base class default constructor
obj2 = obj1; //calls assignment operator

Ví dụ cho hàm tạo bản sao:

Base obj1(5);
Base obj2 = obj1; //calls copy constructor

Công bằng mà nói rằng một toán tử gán kết hợp hiệu quả việc phá hủy một đối tượng cũ với việc tạo một đối tượng mới, nhưng với điều kiện là (1) nếu một trong các bước trong quá trình phá hủy đối tượng cũ sẽ được hoàn tác một trong các bước trong quá trình xây dựng cái mới, có thể bỏ qua cả hai bước; (2) các toán tử gán không nên làm điều xấu nếu một đối tượng được gán cho chính nó.
supercat

tại sao làm vector <A> v3và sau đó v3 = v2 (nơi v2được khai báo trước đó và chứa các phần tử vector<A>) lại gọi hàm tạo Abản sao rõ ràng của tôi thay vì operator=? Tôi đã mong đợi operator=được gọi thay copy constructorv3đối tượng của tôi đã được khai báo tại thời điểm tôi thực hiện nhiệm vụ
Cătălina Sîrbu

19

Đầu tiên là khởi tạo sao chép, thứ hai là chỉ định. Không có cái gọi là hàm tạo phép gán.

A aa=bb;

sử dụng hàm tạo bản sao do trình biên dịch tạo.

A cc;
cc=aa;

sử dụng hàm tạo mặc định để tạo ccvà sau đó là toán tử gán * ** ( operator =) trên một đối tượng đã tồn tại.

Tôi muốn biết cách cấp phát bộ nhớ của hàm tạo gán và hàm tạo sao chép?

Hiểu ý bạn bằng cách cấp phát bộ nhớ trong trường hợp này, nhưng nếu bạn muốn xem điều gì xảy ra, bạn có thể:

class A
{
public :
    A(){ cout<<"default constructor"<<endl;};
    A(const A& other){ cout<<"copy constructor"<<endl;};
    A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};

Tôi cũng khuyên bạn nên xem qua:

Tại sao hàm tạo bản sao được gọi thay vì hàm tạo chuyển đổi?

Quy tắc Ba là gì?


5

Nói một cách đơn giản,

Hàm tạo sao chép được gọi khi một đối tượng mới được tạo từ một đối tượng hiện có, như một bản sao của đối tượng hiện có. Và toán tử gán được gọi khi một đối tượng đã được khởi tạo được gán một giá trị mới từ một đối tượng hiện có khác.

Thí dụ-

t2 = t1;  // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1;  // calls copy constructor, same as "Test t3(t1);"

4

Những gì @Luchian Grigore Said được triển khai như thế này

class A
{
public :
    int a;
    A(){ cout<<"default constructor"<<endl;};
    A(const A& other){ cout<<"copy constructor"<<endl;};
    A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};

void main()
{
    A sampleObj; //Calls default constructor
    sampleObj.a = 10;

    A copyConsObj  = sampleObj; //Initializing calls copy constructor

    A assignOpObj; //Calls default constrcutor
    assignOpObj = sampleObj; //Object Created before so it calls assignment operator
}

ĐẦU RA


nhà xây dựng mặc định


sao chép hàm tạo


nhà xây dựng mặc định


điều hành viên phân công



4

sự khác biệt giữa một hàm tạo bản sao và một hàm tạo gán là:

  1. Trong trường hợp một hàm tạo sao chép, nó sẽ tạo một đối tượng mới. ( <classname> <o1>=<o2>)
  2. Trong trường hợp một hàm tạo gán, nó sẽ không tạo bất kỳ đối tượng nào có nghĩa là nó áp dụng trên các đối tượng đã được tạo ( <o1>=<o2>).

Và các chức năng cơ bản của cả hai đều giống nhau, chúng sẽ sao chép dữ liệu từ o2 sang o1 từng thành viên.


2

Tôi muốn thêm một điểm nữa về chủ đề này. "Hàm toán tử của toán tử gán chỉ nên được viết như một hàm thành viên của lớp." Chúng tôi không thể đặt nó làm hàm bạn bè không giống như các toán tử nhị phân hoặc đơn phân khác.


1

Vài điều cần thêm về hàm tạo bản sao:

  • Khi truyền một đối tượng theo giá trị, nó sẽ sử dụng hàm tạo bản sao

  • Khi một đối tượng được trả về từ một hàm theo giá trị, nó sẽ sử dụng hàm tạo bản sao

  • Khi khởi tạo một đối tượng bằng các giá trị của đối tượng khác (như ví dụ bạn đưa ra).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.