Effective C++學習第三天

1:為多態基類聲明virtual析構函數

? ? ? ?當我們創建一個base class指針指向新生成的derived class時,當刪除基類指針時,如果base class是一個non-virtual析構函數時,實際執行的結果通常是derived class中的base成分被銷毀,derived成分沒有被銷毀;

? ? ? 通常解決這種問題的方法是把base class中的析構函數聲明為virtual;

? ? ? 并不是只有析構函數可以聲明為virtual,其他的函數也可以,virtual函數的目的是為了讓derived class客制化,也就是實現動態聯編;

? ? ?任何class中只要帶有virtual函數都需要提供一個virtual析構函數;

? ? 想要實現虛函數,對象必須提供某些信息,來決定運行期決定那個virtual函數被調用,通常這個信息有vptr(virtual table pointer)來表示,vptr指向一個函數指針構成的數組,稱為vtbl(virtual table),每一個帶有virtual函數的class都有一個對應的vtbl,對象調用virtual函數的時候,實際上調用的是vptr指向的vtbl;

? ? ?一般來說,如果不想把base class用于繼承,一般不要定義virtual函數,畢竟vptr指針會占內存的;不要試圖去繼承一個不帶虛析構函數的類,這樣會出問題的;

? ? ?抽象類(不能被實體化的類,不能用這種類來創建對象):類中帶一個pure virtual析構函數,通常作為base classes;由于析構的順序和初始化的順序相反,因此在聲明純虛析構函數時,需要給虛析構函數提供一份定義,這樣編譯器在derived class的析構函數創建一個對base class析構函數的調用動作,即使在base class中未發生析構,代碼如下:

?class AMOV{

public:

? ? ? ? ?virtual ~AMOV() =0;//pure virtual析構函數

};

AMOV::~AMOV() { }

? ? 結論:polymorphic(帶多態性質的)base classes應該聲明一個virtual析構函數,如果class帶有任何的virtual函數,那么應該有一個virtual析構函數;

? ? ? ? ? ? ?classes的設計目的如果不是作為base classes使用,或不是為了多態性就不應該聲明virtual析構函數;

2:別讓異常逃離析構函數

? ? ? ? 在兩個異常同時存在的情況下,程序若不結束執行就會導致不明確的行為;

class dbconnection{? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?class dbconn{//管理對吧connection對象

public:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?public:

? ? ? ? ? static dbconnction create();//創建對象? ? ? ? ? ? ? ? ? ? ? ? ? ?~dbconn()? {? ? ? db.close() ;? ?}//關閉數據庫連接

? ? ? ? ? void close();//關閉系統? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?private:? dbconnection db;

};? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?};

?問題:如果close()調用失敗,就會產生異常,而析構函數中沒有處理異常的機制,異常在析構函數向上拋出;

解決方案:在析構函數中建立異常處理機制或者直接吞掉異常(如果在吞掉異常后,程序依舊可以可靠的運行);? ? ? ? ? ? ? ? ? ? ~dbcnn(){

? ? ? ? ? ? ? ?try {db.close();}

? ? ? ? ? ? ? ?catch(...){//捕獲異常

? ? ? ? ? ? ? ? ? ? ? ? ? ?std::abort() ;//終止程序? ? ? ? ? ? ? //方案1需要這一句? ? ? ? //方案2不需要

? ? ? ? ? ? ? ? ? ? ? ? ? }

}

另外一種比較好的方法就是:重新設計dbconn接口,設置一個普通函數讓用戶判斷是否會產生異常,

class dbcnn{

public:

?void close(){

? ? ? ? ? ? ?db.close();

? ? ? ? ? ? ?closed=true;

? ? ? ? ? ? ?}?

~dbcnn() {

if(!closed){

? ? ? ? try{

? ? ? ? ? ? ? ? db.close();

? ? ? ? ?}

? ? ? ? ?catch(...){

? ? ? ? }

? ? }

? }

private:

? ? ? ? ? ? dbconnection db;

? ? ? ? ? ? bool closed;

};

3:不要在構造和析構函數中調用virtual函數

? ? ? ? ? 對于構造函數而言,不能在構造過程中調用virtual函數的原因:base class在構造過程中,virtual函數不會下降到derived class,因為在base class構造函數執行時derived class的成員還沒有初始化,如果此時virtual函數下降到derived class中,勢必會調用未初始化的變量,而C++不允許這一現象發生,在base class構造期間,virtual函數不再是virtual函數;更本質的原因是在derived class對象的base class構造期間,對象是base class而不是derived class,不只是virtual函數會被編譯器解析為base class,若使用運行期類型信息(如dynamic_cast和typeid),也會把對象視為base class類型,因此對象在derived class構造函數開始執行前不會成為一個derived class對象;

? ? ? ? ?對于析構函數也是同樣的道理(構造和析構的順序相反):一旦derived class析構函數開始執行,對象內的derived class成員變量便呈現出未定義狀態(因為被析構了),進入base class析構函數后對象變成一個base class對象;

? ? ? ? 為了防止傳值過程中出現意外指向未初始化的成員變量,可以充分利用static關鍵字;

4:令operator=返回一個reference to*this

? ? ? 為了使操作符實現連鎖操作,操作符必須返回一個reference指向操作符的左側實參;


? ? ?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382395.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382395.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382395.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux創建指定大小的文件

一、生成文件大小和實際占空間大小一樣的文件 dd if/dev/zero ofname.file bs1M count1 文件名稱name.file bs1M表示每一次讀寫1M數據,count50表示讀寫 50次,這樣就指定了生成文件的大小為50M。 二、生成文件大小固定,但實際不占空間命令 …

Effective C++學習第四天

條款11:在operator中處理自我賦值的現象雖然我們在平時可能不會出現顯示自我賦值的現象,當加入指針或者引用時,可能會出現不同的指針或引用指向同一對象(對象的不同別名),這時候我們就得考慮對象是否是同一…

Effective C++學習第五天

條款14:在資源管理類中小心copy行為當我們深入理解“資源取得時機是初始化時機(RAII)”概念,并以此作為“資源管理類”的核心時,我們可能會遇到將RAII對象復制的情況,一般有兩種情況處理這個現象&#xff1…

Redis運維和開發學習筆記(2) redis持久化

Redis運維和開發學習筆記(2) redis持久化 文章目錄Redis運維和開發學習筆記(2) redis持久化持久化持久化方式一:RDB觸發~~的三種~~方式1. save命令2. bgsave配置觸發機制RDB 總結持久化方式二:AOFAOF的三種策略三種策略的優缺點AOF重寫機制持久化 redis將所有數據保存在內存中&…

Effective C++學習第六天

條款18:讓接口更容易被正確使用,不易被誤用設計接口的原則:正確性、高效性、封裝性、維護性、延展性以及協議的一致性;設計原則:1)導入新類型來預防很多客戶端的錯誤,多使用系統類型&#xff08…

Redis運維和開發學習筆記(4) Redis參數意義

Redis運維和開發學習筆記(4) Redis參數意義 文章目錄Redis運維和開發學習筆記(4) Redis參數意義參數意義參數意義 Client連接 問題 id567800790 addr10.18.17.217:37310 fd1572 name age2039114 idle2034860 flagsN db0 sub0 psub0 multi-1 qbuf0 qbuf-free0 obl0 oll0 omem0 …

Effective C++學習第七天

條款23:寧以non-memeber、non-friend替換member函數non-member/non-friend可以給對象帶來更大的封裝性,從兩個方面來考慮:1)考慮封裝,越多東西被封裝,它們就越不可見,就越少人看到它&#xff0c…

Redis運維和開發學習筆記(5) 主從復制和sentinel哨兵模式

Redis運維和開發學習筆記(5) 主從復制和sentinel哨兵模式 主從復制 將主節點的數據改變同步給從節點 作用 備份數據讀寫分離 存在的問題: 手動干預切主等操作主節點的寫能力受到單機限制主節點的存儲能力受到單機限制 主從模式的故障恢復 當主節點發生故障時&am…

Effective C++學習第八天

條款26:盡可能延后變量定義式的出現時間當你定義了一個變量,如果在使用變量之前出現異常,那么你得承受一次構造成本和析構成本,而且你沒有使用該變量;本條款給出的建議是延遲變量的定義,直到非得使用該變量…

Redis運維和開發學習筆記(6) 監控Redis工作狀態-info命令

Redis運維和開發學習筆記(6) 監控Redis工作狀態-info命令 文章目錄Redis運維和開發學習筆記(6) 監控Redis工作狀態-info命令info serverinfo clientinfo memoryinfo persistenceinfo statsinfo commandstatsinfo cpuinfo clusterinfo keyspaceinfo server Redis服務器相關的通用…

Effective C++學習第九天

條款32:確定你的public繼承塑模出is-a模型class D(derived)以public形式繼承class B(base),則每一個類型為D的對象同時也是一個類型為B的對象,反之不成立,因此B比D表現出更加一般化的…

Effective C++學習第十天

條款36:絕不重新定義繼承而來的non-virtual函數non-virtual函數執行的是靜態綁定,在編譯器就已經決定,因此對象對用的函數只和指針的類型有關,而與指針所指的對象無關;記住non-virtual函數的性質:不變性凌駕…

Redis運維和開發學習筆記(7) 內存管理和過期策略

Redis運維和開發學習筆記(7) 內存管理和過期策略 文章目錄Redis運維和開發學習筆記(7) 內存管理和過期策略內存回收策略惰性刪除定時任務刪除maxmemory過期策略allkeys-lru主從搭建測試搭建完畢主從測試結果volatile-lru測試結果volatile-ttl測試結果allkeys-lru內存回收策略 …

Effective C++學習第十一天

條款41:了解隱式接口和編譯期多態面向對象編程世界總是以顯式接口(源碼可見的接口)和運行期多態(virtual)解決問題;對于templates及泛型編程的世界,隱式接口和編譯期多態顯得更加重要&#xff1…

Redis源碼分析(零)學習路徑筆記

文章目錄第一階段第二階段 熟悉Redis的內存編碼結構第三階段 熟悉Redis數據類型的實現第四階段 熟悉Redis數據庫的實現第五階段 熟悉客戶端和服務器端的代碼實現第六階段 這一階段主要是熟悉Redis多機部分的代碼實現關于測試方面的文件有一些工具類的文件如下SORT命令的實現一些…

Effective C++學習第十二天

條款47:請使用traits classes表現類型信息STL有五類迭代器分類,input迭代器(只讀,一次,向前)、output迭代器(可寫,一次,向前)、forward迭代器(讀/…

Redis源碼分析(一)redis.c //redis-server.c

Redis源碼分析(一)redis.c //redis-server.c 入口函數 int main() 4450 int main(int argc, char **argv) {4451 initServerConfig();4452 if (argc 2) {4453 ResetServerSaveParams();4454 loadServerConfig(argv[1]);4455 …

Linux 學習

1.linux文本命令行語言環境設置命令 查看當前語言環境: echo ¥LANG 修改: LANG選擇的語言環境’ 引申:https://blog.csdn.net/huoyunshen88/article/details/41113633 2.linux中的硬鏈接和軟連接 linux中文件的儲存方式&#xf…

vivo C/C++工程師視頻面試總結 20180802

1.自我介紹:有點兒緊張了,直接把自己簡歷上的一些信息信息說了一遍,說完之后在介紹了一下自己的平時的愛好和興趣,感覺面試官沒有理我,直接進入下一環節了。 2.項目詳情:主要是自己最近的一個項目和自己負…

Redis源碼分析(二)redis-cli.c

文章目錄1. int main()2. parseOptions(int argc, char **argv) 進行ip和port的改變3. lookupCommand(char *name) 查找命令,判斷命令合法3.2 strcasecmp(name,cmdTable[j].name)3.1 redisCommand cmdTable[]4. cliSendCommand(int argc, char **argv)4.1 cliConnec…