目錄
我是練習時長一年的 c++ 個人練習生,喜歡野指標、模板報錯和未定義行為(undefined beh**ior)。之前在寫設計模式的『工廠模式』時,一腳踩到了構造、繼承和 new 組合起來的坑,現在也有時間來整理一下了。
眾所周知:在建立物件時,防止有些成員沒有被初始化導致不必要的錯誤,在建立物件的時候自動呼叫建構函式(無宣告型別),完成成員的初始化。即:
class c // 隱式,預設建構函式
class c = class() // 顯示,預設建構函式
class c = class("name") // 顯示,非預設建構函式
class* c = new class // 隱式,預設建構函式
using namespace std;
class stone ;
double radius;
public:
stone() ;
stone(int w, double r) : weight, radius
void showinfo()
};int main ()
觀察以下的**,我們發現 stone s2;s2 = 3.3; 這樣將乙個 double 型別的資料賦值給類型別並沒有出錯,這是隱式型別轉換,從引數型別到類型別。
using namespace std;
class stone ;
double radius;
public:
stone() ;
// 都關閉
stone(double r) : radius
stone(int w) : weight
void showinfo()
};int main ()
這是因為:接受乙個引數的建構函式允許使用賦值語法來為物件賦值。s2=3.3 會建立 stock(double) 臨時物件,臨時物件初始化後程式設計客棧,逐成員賦值的方式複製到物件中,在幾個建構函式中加入了 cout << this 的語句,由物件的位址不同,可以判斷該賦值語句額外生成了臨時物件。
為了防止隱式轉換帶來的危險,可以使用關鍵字 explicit 關閉這一特性,這樣就得顯式完成引數型別到類型別的轉換:s = stock(1.3);不過,得保證沒有二義性。
using namespace std;
class stone ;
double radius;
public:
stone() ;
// 都關閉
explicit stone(double r) : radius
explicit stone(int w) : weight
void showinfo()
};int main ()
上述**中,如果 stone(int w) 沒有被關閉,那麼 s2=3.3 將呼叫這一建構函式。所以建構函式建議都加上 explicit 宣告。
派生類要注意的是:派生類被構造之前,通過呼叫乙個基類的建構函式,建立基類完成基類資料成員的初始化;也就是說,基類物件在程式進入派生類建構函式之前被建立。那麼,可以通過初始化列表傳遞給基類引數,不傳遞的話,呼叫基類的預設的建構函式,如下述程式中的:gem(){}:stone()。
using namespace std;
class stone ;
double radius;
public:
stone() ;
stone(int w, double r) : weight, radius {};
void showinfo()
int getweight()
auto getradius() -> double
};class gem : public stone ;
gem(double p, int w, double r) : stone(w, r), price {};
void show()
};int main ()
物件過期時,程式會呼叫物件的析構函式完成一些清理工作,如釋放變數開闢的空間等。如建構函式使用了 new 來申請空間,析構就需要 delete 來釋放空間。如果沒有特別宣告析構函式,編譯器會為類提供預設的析構函式,在物件作用域到期、被刪除時自動被呼叫。
如 stock1 = stock(),這種就申請了乙個臨時變數,變數消失時會呼叫析構函式。此外,這種區域性變數放在棧區,先入後出,也就是,最後被申請的變數最先被釋放。
using namespace std;
class stone ;
double radius;
public:
stone() ;
~stone()
};int main ()
return 0;
}繼承模擬較容易理解,畢竟都學過物件導向。公有繼承的時候,基類的公有成員也是派生類的共有成員;私有成員也是派生類的一部分,不過需要共有或保護方法來訪問。但是但是但是,派生類和基類的析構函式之間,也是乙個坑。在繼承中:
在繼承中,物件的銷毀順序和建立相反。建立時先建立基類,而後建立子類;銷毀時,先呼叫子類的析構函式,而後自動呼叫基類的析構函式。因此,對於基類而言,建議將析構函式寫成虛方法。如果析構不是虛方法,對於以下情況,只有基類的析構被呼叫;如果析構是虛方法,子類、基類的析構方法都被呼叫。可以嘗試刪除下述**的 virtual 來觀察結果:
using namespace std;
class stone ;
double radius;
public:
stone() ;
stone(int w, double r) : weight, radius {};
void showinfo()
int getweight()
auto getradius() -> double
virtual ~stone()
};class gem : public stone ;
gem(double p, int w, double r) : stone(w, r), price {};
void show()
~gem()
};int main ()
大概常見的坑在上面都記錄好了,來看一段我寫的危險的程式(我大概抽象了一下),覆蓋了:野指標和為定義行為:
using namespace std;
class a
~a()
};int main ()
C 之建構函式和析構函式
我們已經知道了物件就是類的例項,二者的關係就相當於資料型別與它的變數的關係。每個物件區別於其他物件的地方就是依靠它的自身屬性,即資料成員的值。c 中,物件在定義的時候進行的資料成員的設定,稱為物件的初始化。同樣,在特定物件使用結束時,還要對資料成員進行一些清理工作。c 中對類的初始化和清理的工作,分...
C 之建構函式和析構函式
一 建構函式 1 物件的初始化和建構函式 類是一種抽象的資料型別,它不占用儲存空間,不能容納具體的資料。因此在類宣告中不能給資料成員賦初值。例如 錯誤 class complex 與使用變數一樣,使用物件時也應該先定義,後使用。在定義物件時,對資料成員賦初值,稱為初始化。例如 class compl...
C 之建構函式和析構函式強化
構造與析構呼叫順序 include class test9 1 析構的順序和構造的順序相反,先構造的後析構 test9 1 private int m a 物件初始化列表,解決乙個類中有另乙個沒有無參構造的類的物件的初始化 class test9 2 test9 2 private test9 1 ...