// 一般建構函式
String::String(const char* str) {
if (str == NULL) {
m_data = new char[1];
*m_data = '\0';
} else {
int length = strlen(str);
m_data = new char[length + 1];
strcpy(m_data, str);
}
}
// 解構函式
String::~String() {
delete[] m_data; // m_data 為內建型別指標,寫成 delete m_data 亦可
}
並非所有物件都會用到複製建構與指派,程式設計師容易輕視它們。請銘記以下警示:
若類別含指標成員,編譯器生成的預設複製建構/指派函式會執行位元逐位拷貝(淺拷貝)。以 String a("hello"), b("world") 為例,執行 b = a 時:
b.m_data 原有記憶體未釋放。a.m_data 與 b.m_data 指向同一塊記憶體,任一方修改影響另一方。m_data 被 delete 兩次,導致未定義行為。String a("hello");
String b("world");
String c = a; // 呼叫複製建構函式,建議寫成 String c(a);
c = b; // 呼叫指派函式
第三行寫法 String c = a 易與指派混淆,強烈建議改寫為 String c(a) 以明確語意。
// 複製建構函式
String::String(const String& other) {
// 可存取 other 私有成員 m_data
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data, other.m_data);
}
// 指派函式
String& String::operator=(const String& other) {
// (1) 檢查自我指派
if (this == &other) return *this;
// (2) 釋放原有記憶體
delete[] m_data;
// (3) 配置新記憶體並複製內容
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data, other.m_data);
// (4) 回傳自身參考,支援鏈式指派 a = b = c
return *this;
}
NULL,因為「參考」絕不為 NULL,而「指標」可以。delete[] m_data 會導致「自殺後仍嘗試複製」的災難。*this 而非 this 或 other,前者支援鏈式指派,後兩者皆錯誤(other 可能為暫時物件,生命週期不可控)。