面向對象的支持是C++較C的一大區別。面向對象的幾個特色是封裝、繼承、多態。數組
封裝的目的是爲了讓接口和實現分離,這種是邏輯上的分離,而不是在實現時必定要分開定義interface和class。經過封裝,讓類的使用者直接根據須要調用相應接口便可,無需關注接口的實現細節,能夠理解爲是一種數據抽象。安全
最典型的理解,咱們能夠結合標準模板庫來思考,其中有序列式容器,關聯式容器。函數
序列式容器
咱們能夠不關心序列式容器內部的實現機制,無論用數組仍是用列表,可是對外提供了一致的接口,好比:push_back, pop_front等等相似的接口。設計
繼承一方面是業務層面的理解,業務對象之間確實存在這樣的父子關係;從代碼層面爲了代碼複用。子類一方面可使用跟本身特性無關的父類接口,另一方面能夠在自身從新定義跟本身特性相關的接口。指針
繼承模式在GUI相關的技術中應用的特別多,看看MFC中的類繼承體系就可知。code
可是繼承並非惟一能夠重用代碼的途徑,在我看來,組合的方式更易使用。過多的繼承體系讓人難以駕馭!對象
多態是統一代碼的好方式,典型的用法是用父類引用或者父類指針對應各子類對象,並調用相同的函數名;經過動態綁定,運行的是各自對象的各自實現。相對於經過if else的各類判斷,用多態的辦法,一句話就OK。繼承
在設計實現類時,有一些問題須要重點考慮。構造函數、析構函數、拷貝構造函數、賦值操做符重載。接口
構造函數負責在建立對象時,對對象成員的初始化。 這裏有個注意的地方,就是初始化列表以及在構造函數體內的賦值操做。在通常狀況下,這兩種操做並沒有區別,可是若是類成員中有const類型成員或者引用,這種只能初始化,不能賦值。生命週期
class A { public: A(int a_, int b_) { a = a_; b = b_; } private: const int a; int& b; };
error C2789: 「A::a」: 必須初始化常量限定類型的對象 error C2530: 「A::b」: 必須初始化引用 error C2166: 左值指定 const 對象
能夠看到,這種狀況下編譯器會報錯。
拷貝構造函數是用同類型的對象去初始化自身。通常定義格式是:
A(const A& rhs);
類的實現着本身定義相同類型不一樣對象之間的拷貝行爲。通常涉及到指針狀況時,本身去實現該函數,比較安全;
賦值操做符是用同類型的對象給自身賦值,通常定義爲:
A& operator=(const A& rhs)
對於賦值操做符,要考慮不能自身賦值自身的問題。
析構函數是當對象生命週期到達時,被自動調用的函數,非用戶主動調用。若是對象中申請了資源,就在析構函數中進行釋放。通常在存在繼承關係的狀況下,將析構函數定義爲虛函數。
若是某些類的對象做者認爲在內存中應該只有一份,不該該拷貝來拷貝去,那麼能夠將類實現爲uncopyable類型。怎麼實現呢?
private: A(const A& rhs); A& operator(constA& rhs);
將類的拷貝構造函數和賦值操做符設置爲private便可。當發生賦值操做值,因爲調用了private類型的方法,是非法操做。編譯器沒法經過。
新版本的C++能夠經過以下方式作到禁用拷貝,將涉及到拷貝的函數聲明爲delete
class C { public: C(int a_, int b_) : a(a_), b(b_) {} C(const C& rhs) = delete; C& operator=(const C& rhs) = delete; int a; int b; };
當編寫了拷貝代碼時,編譯器會報以下錯誤:
error C2280: 「C &C::operator =(const C &)」: 嘗試引用已刪除的函數
在某些領域,使用面向對象方法能夠很好的提煉出各類業務模型和接口,好比說作GUI,使用面向對象的方法就很是天然;在其餘的系統中,咱們有時候會使用基於對象的方法去作開發,下降程序的複雜度。