1. 程式人生 > >筆記:條款12: 複製物件時勿忘其每一個成分

筆記:條款12: 複製物件時勿忘其每一個成分

這是我在閱讀Effective c++中認為比較重要的部分,下面給出了我對這一節的理解,並寫出對應的比較容易理解的程式碼。   

如果你宣告自己的copying函式(拷貝構造,拷貝賦值),那麼編譯器在你做出錯誤的動作時不會告訴你,下面定義的copying函式沒有對Defau賦值或初始化,而編譯器不會管。

class Defau {
public:
	int i = 10;
};
class A {
public:
	A() = default;
	A(const A&rhs):name(rhs.name){}
	A& operator = (const A&rhs) {
		this->name = rhs.name;
	}
	string name;
	Defau u;
};
int main() {
	A a;
	a.u.i = 15;
	A b(a);
	cout << b.u.i;
}

    而發生繼承時,會造成更大的危機。例如下面程式碼發生的拷貝和賦值操作沒有對子類中的父類成分進行初始化或賦值,而編譯器對此的做法是呼叫父類的預設建構函式。

class B : public A {
public:
	B():prio(3){}
	int prio;
	B(const B&ur):prio(ur.prio){}
	B& operator =(const B&ur) {
		prio = ur.prio;
		return *this;
	}
};

    而正確的做法是讓子類的拷貝建構函式的初始化列表呼叫父類的建構函式,拷貝賦值函式呼叫父類的拷貝賦值函式。

class Defau {
public:
	int i = 10;
};
class A {
public:
	A() = default;
	A(const A&rhs):name(rhs.name),u(rhs.u){}
	A& operator = (const A&rhs) {
		this->name = rhs.name;
		this->u = rhs.u;
		return *this;
	}
	string name;
	Defau u;
};

class B : public A {
public:
	B():prio(3){}
	int prio;
	B(const B&ur):prio(ur.prio),A(ur){}
	B& operator =(const B&ur) {
		prio = ur.prio;
		A::operator=(ur);
		return *this;
	}
};
int main() {
	B b;
	b.u.i = 15;
	b.prio = 6;
	b.name = "dewdqw";
	B c(b);
	cout << c.u.i << endl;
	cout << c.prio << endl;
	cout << c.name;
}

請記住

Copying函式應該確保複製“物件內的所有成員變數”及“所有base class成分”。

不要嘗試以某個copying函式實現另一個copying函式。應該將共同機能放進第三個函式中,並由兩個copying函式共同呼叫。