拷貝聽起來真高級
拷貝構造函數形如c++
class_name(const class_name &object_name)
拷貝構造函數是一種特殊的構造函數,只有一個參數,這個參數是本類中的一個對象,以引用的形式傳參,通常用const修飾,使參數值不變。函數
若是沒有定義拷貝構造函數,編譯器會自動隱式生成一個拷貝構造函數,用來簡單的複製類中每一個成員變量。this
一個簡單的類對象拷貝spa
#include <bits/stdc++.h> using namespace std; class A { private : int a, b; public : A(int x, int y) : a(x), b(y) {} void print() { printf("%d %d\n", a, b); } }; int main() { A a(10, 20); A b = a; b.print(); return 0; }
輸出指針
10 20code
具體看一下拷貝構造函數怎麼用。對象
#include <bits/stdc++.h> using namespace std; class A { private : int a, b; public : A(int x, int y) : a(x), b(y) {} A(const A &c) { a = c.a; b = c.b; } void print() { printf("%d %d\n", a, b); } }; int main() { A a(10, 20); A b = a; b.print(); return 0; }
這樣手動的寫如何複製blog
爲何用引用的方式傳參呢。
舉個反例遞歸
#include <bits/stdc++.h> using namespace std; class A { private : int a; public : A(int x) : a(x) {} A(const A c) { a = c.a; } void print() { printf("%d\n", a); } }; int main() { A a(10); A b = a; b.print(); return 0; }
A b = a
時,調用了傳值型的拷貝構造函數,
至關於b.A(a)
,
由於是傳的值,因此要用a的值建立一個副本對象c
,讓c
的值爲a
,則又須要調用構造函數c.A(a)
,這樣會無限創造副本對象c
,無限調用c.A(a)
;
因此
引用是爲了防止無限遞歸。
其實沒有加引用的話編譯器也是不過編譯的。內存
1. 對象須要經過另外一個對象對其進行賦值
A a(10, 20); A b = a;
2. 當函數的參數是類的對象
#include <bits/stdc++.h> using namespace std; class A { private : int a, b; public : A(int x, int y) : a(x), b(y) {} A(const A &c) {a = c.a, b = c.b;} void print() {printf("%d\n", a * b);} }; void fun(A c) { //函數的形參是類的對象 c.print(); } int main() { A a(10, 20); fun(a); //實參是類的對象,調用函數時將複製一個新對象c return 0; }
3. 當函數的返回值是類的對象
#include <bits/stdc++.h> using namespace std; class A { private : int a, b; public : A(int x, int y) : a(x), b(y) {} A(const A &c) {a = c.a, b = c.b;} void print() {printf("%d\n", a * b);} }; A fun() { A b(20, 10); return b; //函數的返回值是類的對象 } int main() { A a = fun(); //fun()返回 A 類的臨時對象,並賦值給a a.print(); return 0; }
默認拷貝構造函數能夠完成對象的數據值得簡單複製,這就是淺拷貝。
對象的成員是指向堆時,淺拷貝只是將指針簡單複製一遍,指向了原有的內存,而深拷貝是將新建的指針指向了一塊新的內存。
淺拷貝就是將數據簡單複製一下,就像上面講的。
看這段代碼
#include <bits/stdc++.h> using namespace std; class A { private : int *p; public : A(int x) { p = new int(x); printf("Constructor\n"); } A(const A &oth) { this->p = new int(*oth.p); printf("Constructor\n"); } ~A() { if (p != NULL) delete p; printf("Destructor\n"); } void print() { printf("%d\n", *p); } }; int main() { A a(10); A b = a; return 0; }
這是段代碼出錯了,爲何?
如圖所示,
b把a的指針簡單複製了一遍,二者都指向了同一塊內存,釋放內存的時候被釋放了兩次,致使出錯。
對於上面的代碼,咱們手寫一個拷貝構造函數,像這樣
#include <bits/stdc++.h> using namespace std; class A { private : int *p; public : A(int x) { p = new int(x); printf("Constructor\n"); } A(const A &oth) { this->p = new int(*oth.p); printf("Constructor\n"); } ~A() { if (p != NULL) delete p; printf("Destructor\n"); } void print() { printf("%d\n", *p); } }; int main() { A a(10); A b = a; return 0; }
咱們給b初始化時,給它新開闢了一段內存空間
這樣,深拷貝就沒有上述淺拷貝時內存釋放兩次的狀況了。