Time of Update: 2017-02-27
我這篇文章的主旨是介紹一部分類和介面的高品質設計的準則。這些準則不但應該保證設計並且實現的類或者介面本身有高品質代碼,而且更重要的是在工業領域應該儘可能的使代碼的更新和維護不影響客戶的活動,主要也就是保持二進位代碼相容(binary compatibility)和原始碼相容(source
Time of Update: 2017-02-27
很久以前(八十年代),沒有辦法區分++和--操作符的首碼與尾碼調用。這個問題遭到程式員的報怨,於是C++語言得到了擴充,允許重載increment 和 decrement操作符的兩種形式。然而有一個句法上的問題,重載函數間的區別決定於它們的參數類型上的差異,但是不論是increment或decrement的首碼還是尾碼都只有一個參數。為瞭解決這個語言問題,C++規定尾碼形式有一個int型別參數,當函數被調用時,編譯器傳遞一個0做為int參數的值給該函數:class UPInt { //
Time of Update: 2017-02-27
很老的問題了。今天稍微總結了下,有遺漏的地方和錯誤的地方還望大家補充。關於使用大括弧初始化class和struct如果定義了建構函式的話,都不能用大括弧進行初始化如果沒有定義建構函式,struct可以用大括弧初始化。如果沒有定義建構函式,且所有成員變數全是public的話,可以用大括弧初始化。關於預設存取權限class中預設的成員存取權限是private的,而struct中則是public的。關於繼承方式class繼承預設是private繼承,而struct繼承預設是public繼承。且看如下代
Time of Update: 2017-02-27
與C一樣,C++使用布林運算式簡化求值法(short-circuit evaluation)。這表示一旦確定了布林運算式的真假值,即使還有部分運算式沒有被測試,布林運算式也停止運算。例如:char *p;...if ((p != 0) && (strlen(p) > 10)) ...這裡不用擔心當p為空白時strlen無法正確運行,因為如果p不等於0的測試失敗,strlen不會被調用。同樣:int rangeCheck(int index){ if ((index <
Time of Update: 2017-02-27
C++沒有直接定義任何用於執行輸入或輸出(IO)的語句。作為代替,IO是通過標準類庫(standard
Time of Update: 2017-02-27
人們有時好像喜歡故意使C++語言的術語難以理解。比如說new操作符(new operator)和operator new的區別。當你寫這樣的代碼:string *ps = new string("Memory
Time of Update: 2017-02-27
概述PC-Lint是一個曆史悠久,功能異常強勁的靜態代碼偵查工具。它的使用曆史可以追溯到電腦編程的遠古時代(30多年以前)。經過這麼多年的發展,它不但能夠監測出許多文法邏輯上的隱患,而且也能夠有效地幫你提出許多程式在空間利用、運行效率上的改進點,在很多專業級的軟體公司,比如Microsoft,
Time of Update: 2017-02-27
如果你正在開發一個具有多媒體功能的通訊錄程式。這個通訊錄除了能儲存通常的文字資訊如姓名、地址、電話號碼外,還能儲存照片和聲音(可以給出他們名字的正確發音)。為了實現這個通訊錄,你可以這樣設計:class Image { // 用於映像資料 public: Image(const string& imageDataFileName); ...};class AudioClip { // 用於聲音資料 public: AudioClip(const string&
Time of Update: 2017-02-27
在有兩種情況下會調用解構函式。第一種是在正常情況下刪除一個對象,例如對象超出了範圍或被顯式地delete。第二種是異常傳遞的堆棧輾轉開解(stack-unwinding)過程中,由異常處理系統刪除一個對象。在上述兩種情況下,調用解構函式時異常可能處於啟用狀態也可能沒有處於啟用狀態。遺憾的是沒有辦法在解構函式內部區分出這兩種情況。因此在寫解構函式時你必須保守地假設有異常被啟用,因為如果在一個異常被啟用的同時,解構函式也拋出異常,並導致程式控制權轉移到解構函式外,C++將調用terminate函數。
Time of Update: 2017-02-27
從文法上看,在函數裡聲明參數與在catch子句中聲明參數幾乎沒有什麼差別:class Widget { ... }; //一個類,具體是什麼類// 在這裡並不重要void f1(Widget w); // 一些函數,其參數分別為void f2(Widget& w); // Widget, Widget&,或void f3(const Widget& w); // Widget* 類型void f4(Widget *pw);void f5(const Widget *pw)
Time of Update: 2017-02-27
當你寫一個catch子句時,必須確定讓異常通過何種方式傳遞到catch子句裡。你可以有三個選擇:與你給函數傳遞參數一樣,通過指標(by pointer),通過傳值(by value)或通過引用(by reference)。我們首先討論通過指標方式捕獲異常(catch by pointer)。從throw處傳遞一個異常到catch子句是一個緩慢的過程,在理論上這種方法的實現對於這個過程來說是效率最高的。因為在傳遞異常資訊時,只有採用通過指標拋出異常的方法才能夠做到不拷貝對象,例如:class
Time of Update: 2017-02-27
線程同步是多線程程式設計的核心內容,它的目的是正確處理多線程並發時的各種問題,例如線程的等待、多個線程訪問同一資料時的互斥,防死結等。Win32提供多種核心對象和手段用於線程同步,如互斥量、訊號量、事件、臨界區等。所不同的是,互斥量、訊號量、事件都是Windows的核心對象,當程式對這些對象進行控制時會自動轉換到核心態,而臨界區本身不是核心對象,它是工作在使用者態的。我們知道從使用者態轉換到核心態是需要以時間為代價的,所以如果能在使用者態就簡單解決的問題,就可以不必勞煩核心態了。這裡我要說的是兩
Time of Update: 2017-02-27
上一篇中我介紹了一種通過封閉Critical
Time of Update: 2017-02-27
object-oriented programming(物件導向編程)的世界是圍繞著 explicit interfaces(顯式介面)和 runtime polymorphism(執行期多態)為中心的。例如,給出下面這個(沒有什麼意義的)的 class(類)。class Widget { public: Widget(); virtual ~Widget(); virtual std::size_t size() const; virtual void
Time of Update: 2017-02-27
我們再看看虛成員函數的調用。類C041中含有虛成員函數,它的定義如下:struct C041{C041() : c_(0x01) {}virtual void foo() { c_ = 0x02; }char c_;};執行如下代碼:C041 obj;PRINT_DETAIL(C041, obj)PRINT_VTABLE_ITEM(obj, 0, 0)obj.foo();C041 * pt = &obj;pt->foo();結果如下:The detail of C041 is 14
Time of Update: 2017-02-27
觸及 multiple inheritance (MI)(多繼承)的時候,C++ 社區就會鮮明地分裂為兩個基本的陣營。一個陣營認為如果 single inheritance (SI)(單繼承)是有好處的,multiple inheritance(多繼承)一定更有好處。另一個陣營認為 single inheritance(單繼承)有好處,但是多繼承引起的麻煩使它得不償失。在本文中,我們的主要目的是理解在 MI 問題上的這兩種看法。首要的事情之一是要承認當將 MI
Time of Update: 2017-02-27
從這部分開始我們除了利用記憶體的資訊列印來進行探索外,更多的會通過跟蹤和觀察編譯器產生的彙編代碼來理解編譯器對這些語言特性的實現方式。彙編方面知識的討論超出了本文的範圍,我只對和我們討論相關的彙編代碼進行解析。理解本文要討論的知識並不需要有很完整的彙編知識,但必須瞭解起碼的概念。下面我們看看引入虛繼承後的影響。為了有所對比我們首先看看普通成員函數的調用情況。執行如下代碼,它包括了對象的普通成員函數調用,類的靜態成員函數調用、通過指標調用普通成員函數:C010 obj;PRINT_OBJ_ADR(
Time of Update: 2017-02-27
在《C++箴言:確保公開繼承類比“is-a”》一文中論述了 C++ 將 public inheritance(公有繼承)視為一個 is-a 關係。當給定一個 hierarchy(繼承體系),其中有一個 class Student 從一個 class Person 公有繼承,當為一個函數調用的成功而有必要時,需要將 Students 隱式轉型為 Persons,它通過向編譯器展示來做到這一點。用 private inheritance(私人繼承)代替 public
Time of Update: 2017-02-27
為了驗證前面提到過的類型動態轉換(即dynamic_cast轉換),以及物件類型的強制轉換。我們利用前面定義的C041、C042及C082類來進行驗證。運行下列代碼:c082.C041::c_ = 0x05;PRINT_VTABLE_ITEM(c041, 0, 0)PRINT_DETAIL(C041, ((C041)c082))PRINT_VTABLE_ITEM(((C041)c082), 0, 0)PRINT_VTABLE_ITEM(c082, 5, 0)C042 * pt =
Time of Update: 2017-02-27
假設我告訴你 class(類)D 從 class(類)B publicly derived(公有繼承),而且在 class(類)B 中定義了一個 public member function(公有成員函數)mf。mf 的參數和傳回值類型是無關緊要的,所以我們就假設它們都是 void。換句話說,我的意思是:class B { public: void mf(); ...};class D: public B { ... };甚至不必知道關於 B,D,或 mf 的任何事情,給定一個類型為 D