Time of Update: 2018-12-06
為什麼有人想要替換operator new 和 operator delete呢?三個常見的理由:1.用來檢測運用上的錯誤。如果將“new所的記憶體”delete卻不幸失敗,會導致記憶體流失。如果在“new所得記憶體”身上多次delete會導致不確定行為。如果new持有一串動態分配的所得地址,operator delete將地址從中移走,倒是很容易檢測出上述錯誤用法。此外各式各樣的編程錯誤可能導致資料“overruns”(寫入點在分配區塊尾端之後)或“underruns”(寫入點在分配區塊之前)
Time of Update: 2018-12-06
c++明確指出,當derived class對象由一個base class指標刪除,而該base class帶著一個non-virtual解構函式,其結果未有定義—實際執行時,通常發生的是對象的derived成分沒被銷毀。會造成“局部銷毀”對象。 而避免這個問題很簡單:給base class一個virtual解構函式。任何class只要帶有virtual函數,都幾乎確定應該有一個virtual解構函式。如果class不含virtual函數,通常表示它並不意圖被用作一個base
Time of Update: 2018-12-06
假設你對c++程式的某個class實現檔案做了些輕微改變,修改的不是介面,而是實現,而且只改private成分。然後重建立置這個程式,並預計只花數秒就好,當按下“Build”或鍵入make,會大吃一驚,因為你意識到整個世界都被重新編譯和連結了!問題是在c++並沒有把“將介面從實現中分離”做得很好。class 的定義式不只詳細敘述了class介面,還包括十足的實現細目:class Person{ public: Person(const std::string&
Time of Update: 2018-12-06
物件導向編程世界總是以顯示介面(explicit interface)和運行期多態(runtime polymorphism)解決問題。class Widget{ public: Widget(); virtual ~Widget(); virtual std::size_t size() const; virtual void normalize(); virtual
Time of Update: 2018-12-06
class B{ public: virtual void f() const; };class D: public B{ public: virtual void f(); };這裡希望重新定義virtual函數B::f,但有個錯誤,B中的f是個const成員函數,但D中未被聲明const。有編譯器就這樣說:warning:D::f() hides virtual
Time of Update: 2018-12-06
如果你令class D以public形式繼承class B,你便是告訴c++編譯器,每一個類型為D的對象同時也是一個類型為B的對象,反之不成立。B比D表現出更一般化的概念,D比B更特殊化的概念。任何函數如果期望獲得一個類型為B(或pointer to B或reference-to-B)的實參,都也願意接受一個D對象(或pointer-to-D或reference-to-D)。這個論點只有對public繼承才成立。class Bird{ virtual void fly(); //
Time of Update: 2018-12-06
考慮有理數的class:class Rational { public: Rational(int numerator = 0, int denominator = 1); protected: private: int n, d; friend Rational operator*(const Rational& lhs, const Rational& rhs); };by
Time of Update: 2018-12-06
賦值的連鎖式 x=y=z=3;被解析成x=(y=(z=3));為了實現“連鎖賦值”,賦值操作符必須返回一個reference指向操作符的左側實參,這是你為class實現賦值操作符時應該遵循的協議:class Widget { public: Widget& operator=(const Widget& rhs) //傳回型別是reference, {
Time of Update: 2018-12-06
template聲明式中,class和typename這兩個關鍵字意義完全相同template<class T> class Widget;template<typename T> class Widget;有時候你一定要用typename,可以在template中指涉的兩種名稱:template <typename C> void print2nd(const C& container) { if
Time of Update: 2018-12-06
實現一致性operator new必須返回正確的值,記憶體不足時必須調用new_handling函數,必須有對付零記憶體的準備,還需要避免不慎掩蓋正常形式的new。void* operator new(std::size_t size) throw(std::bad_alloc) { using namespace std; if (size == 0) { size = 1; }
Time of Update: 2018-12-06
為什麼不採用public成員變數首先,文法一致性考慮,客戶唯一能訪問對象的方法就是通過成員函數,客戶不必考慮是否該記住使用小括弧()。其次,使用函數可以讓你對成員變數的處理有更精確的控制。如果成員變數是public,每個人都可以讀寫它,但是如果你也函數取得或設定其值,你就可以實現“不準訪問”、“唯讀訪問”,以及”讀寫訪問”甚至”唯寫訪問“:class AccessLevels { public: int getReadOnlay() const
Time of Update: 2018-12-06
c++並不禁止解構函式拋出異常,但它不鼓勵這樣做:class Widget{public: … ~Widget(); //假設可能拋出異常};void doSomething(){ std::vector<Widget> v; …}當vector
Time of Update: 2018-12-06
身為class設計者,有時候你希望derived class只繼承成員函數的介面(也就是聲明):有時候你又希望derived class同時繼承函數的介面和實現,但又希望能夠覆寫(override)它們所繼承的實現:又有時候你希望derived class同時繼承函數的介面與實現,並且不允許覆寫任何東西。讓我們考慮一個展現繪圖程式中各種幾何形狀的class繼承體系:class Shape { public: virtual void draw() const = 0;
Time of Update: 2018-12-06
Widget* pw = new Widget;共有兩個函數被調用:一個分配記憶體的operator new,一個Widget的default建構函式。假設第一個調用成功,第二個卻拋出異常。步驟一所分配記憶體必須取消並恢複舊觀,否則會造成記憶體流失。這時,客戶沒能力歸還記憶體,因為Widget建構函式拋出異常,pw尚未被賦值,客戶手上也就沒有指標指向該被歸還的記憶體。取消步驟一,並恢複舊觀的責任就落到c++運行系統身上。運行期系統會高興的調用步驟一所調用operator
Time of Update: 2018-12-06
template是節省時間和避免重複代碼的一個奇妙方法。class template的成員函數只有在被使用時才被暗中具現化。function templates有類似的訴求。但是如果你不小心,使用templates可能導致代碼膨脹(code bloat):其二進位代碼帶著重複(或幾乎重複)的代碼、資料、或兩者。其結果可能源碼看起來合身整齊,但目標碼卻不是那麼回事。你需要知道如何避免這樣的二進位浮誇。主要工具是:共性與變性分析。在non-template中,重複十分明確,然而在template中,
Time of Update: 2018-12-06
每當建立一個交易對象,在審計日誌中也要建立一筆適當記錄。下面是一個看起來比較合理的做法:class Transaction { public: Transaction() { init(); } virtual void logTransaction() const { std::cout << "transaction" ;}; protected:private: void
Time of Update: 2018-12-06
令class支援類型隱式轉換通常是個糟糕的主意。當然這條規定在建立數實值型別時,有例外。假設一個class用來表現有理數,允許整數“隱式轉換為”有理數似乎很合理。class Rational{ public: Rational(int numerator = 0, int denominator = 1); //刻意不為explicit;允許int-to-Rational隱式轉換 int numerator()const; int
Time of Update: 2018-12-06
這個題材其實和繼承無關,而是和範圍(scopes)有關。int x; void someFunc() { double x; std::cin >> x;
Time of Update: 2018-12-06
我們需要一個程式,傳送資訊到不同的公司去。資訊要不譯成密碼,要不就是未加工的文字。如果編譯期間我們有足夠資訊來決定哪一個資訊傳至那一家公司,就可以採用基於template的解法:class CompanyA{ public: void sendCleartext(const std::string& msg); void sendEncrypted(const std::string& msg); }; class
Time of Update: 2018-12-06
有個class來表示網頁瀏覽器:class WebBrowser { public: void clearChache(); void clearHistory(); void removeCookies(); protected: private: };許多使用者會想一整個執行所有這些動作,因此WebBrowser也提供這樣一個函數:clearEverythingclass