面向過程的編程風格
? Procedural Programming
1.?
C++
不允許改變改變
reference
所代表的對象,對
reference
的所有操作與對“
reference
所代表的對象”所進行的操作相同。
2.?
以
by reference
方式傳遞對象當作函數參數時,復制的將是對象的地址,函數中對該對象的所有操作都相當是對傳入的對象進行間接操作。
3.?
pointer
和
reference
的最重要差異是,
pointer
可以為空,使用前一定要確保其值非
0
,而
reference
必定代表某個對象,不必作此檢查。
4.?
編譯器無法根據函數返回值型別來區分兩個具有相同名稱的函數,因為返回值型別無法保證提供我們一個足以區分不同重載函數的情境。
5.?
由函數指針尋址出來的函數,其調用方式和一般函數相同。
6.?
可以給函數指針賦予初值,函數名稱即代表了函數的地址。
7.?
標準的或項目專屬的頭文件應用尖括號擴住;用戶自行提供的頭文件則使用引號。
2002-6-3
泛型編程風格
? Generic Programming
1.?
Standard Template Library (STL)
主要由兩種組件構成:容器
container
和泛型算法
generic algorithm
<
通過
function template
技術,實現與容器及數值類型無關之功能
>
。
2.?
容器分類:
<
切記:
vector
可以是空的,數組則否
>
序列式容器
sequential container
:
vector, list, deque……
關聯式容器
associative container
:
map, set, ……
3.?
iterator
及
const_iterator
實際上是各個容器定義式內的嵌套
nested
型別。
4.?
使用泛型算法須
#include <algorithm>
,使用
function object
須
#include <functional>
。
5.?
function object
是某種
class
的實體對象,該
class
對
function call
運算符進行了重載操作從而可使
function object
被當作一般函數來使用。令
function call
運算符成為
inline
,從而消除“通過函數指針來調用函數“時需付出的額外代價。
6.?
function object adapter
會對
function object
進行修改操作。
7.?
綁定配接器
binder
adapter
<bind1nd, bind2nd>
會使
bineary function object
變成
unary function object
;
negator
adaper
<not1, not2>
會逆轉
function object
的真偽值;另外一種有用的
adapter
叫做
instertion
adapter
<back_inserter, inserter, front_inserter>
。
#include <iterator>
8.?
map
被定義為一對數值,其中
key
通常是個字符串,扮演索引角色,另一個數值是
value
。
9.?
任何一個
key
值在
map
或
set
內最多只有一份,若要多份相同
key
值,使用
multimap
或
multiset
。
完成日期:
2002-6-2
基于對象的編程風格
? Object-Based Programming
1
.在
class
內部定義的
member??
函數被自動視為
inline
函數。對
inline
函數而言,聲明在
class
內部或外部并無區別,同
non-member inline
函數一樣,它應于頭文件中定義。
2
.
Triangular t();
被編譯器視為一個函數定義!并不是聲明或定義一個
Triangular
對象!
3
.以某個
class object
作為另一個
object
的初值時,會發生
default memberwise initialization
<
實際上是自動產生一個
copy constructor>
,可以為該
class
提供一個
copy constructor
來改變這一默認行為模式。
4
.若有必要為
class
撰寫
copy constructor
,則同樣有必要為它撰寫
copy assignment operator
,除非撰寫
copy constructor
的目的僅僅是為了激活編譯器實施
NRV
優化。
5
.凡是在
class
主體以外定義的
const member function
,必須同時在聲明與定義時都提供
const
關鍵字,
const
緊接于函數參數表之后。
6
.
member function
返回一個指向
member data
的
non-const reference
,實際上等于將該
member data
開放出去,允許程序在其它地方加以修改。由于函數可以根據參數
const
與否
??
而重載,故可以提供兩份定義,一份為
const
版本,一份為
non-const
版本。
8.?
設計
class
時,鑒定其
const member function
是一件很重要的事情!
9.?
將
member data
聲明為
mutable
表明:對該
member data
的修改不會破壞
class object
的常數性。
10.?????????????
欲以一個對象復制出另一個對象,先確定兩個對象是否相同是個好習慣。
11.?????????????
運算符的重載規則:不可以引入新的運算符,除了
., .*, ::, ?:
4個運算符,其它運算符皆可被重載;運算符的操作數
operand
不可改變;運算符的優先級不可改變;運算符函數的參數列中必須至少有一個參數為
class
型別。
12
.
increment
和
decrement
運算符的前置及后置版本都可直接施行于
class object
其之上,編譯器會自動為后置版產生一個
int
引數,其值必為
0
。
13
.所謂
friend
,具備了與
class member function
相同的存取權限,可以存取
class
的
private member
。
14
.只要
class
設計者顯示提供了
copy assignment operator
,它就會被用來取代
default memberwise copy
行為。
15
.當編譯器在編譯過程中遇到函數調用,例如
lt(ival)
,
lt
可能是函數名稱,可能是函數指針,也可能是一個提供了
function call
的
function object
。如果
lt
是個
function object
,編譯器會在內部將此語句轉化為:
lt.operator(ival)
;
16
.
function call
可以接受多個運算符,通常將
function object
當作參數傳給泛型算法。
17
.為了取得某個
member function
的地址,只需對函數名稱施以取址
address-of
運算符,同時,函數名稱之前必須先以
class object
運算符加以修飾,而返回型別及參數表皆不需指明,如:
void (classname::*mfptr) (int) = &classname::mfname;
18
.注意所謂的
maximal munch
編譯規則,如:
static vector<vector<int> > seq;
兩個
”>”
號之間必須加有空格,否則無法成功編譯!
19
.
pointer to member function
和
pointer to function
的一個不同點是:前者必須通過同類的對象加以調用。
.*
符號是針對
class object
的
pointer to member selection
運算符,
->*
符號是針對
pointer to class object
的
pointer to member selection
。使用它們時注意必須加上外圍小括號!如:
(classobject.*mfptr)(par);
???????????????????????????????????????????????????????
完成日期:
2002-6-18
?
面向對象編程風格
?? Object-Oriented Programming
1.?
面向對象編程的兩項最主要的特性是繼承
inheritance
和多態
polymorphism
。
2.?
動態綁定
Dynamic binding
是面向對象編程風格的第三個獨特概念,即找出實際被調用的究竟是哪一個派生類的函數。而靜態綁定
Static binding
則在程序運行之前就決議出應該調用哪一個函數。
3.?
多態和動態綁定的特性只有在使用
pointer
或
reference
時才能發揮。
4.?
staitic member function
無法被聲明為虛擬函數。
5.?
任何一個類只要有純虛擬函數,程序就會因其接口的不完整而無法為它產生任何對象,這種類只能作為派生類的子對象
subobject
之用,而且派生類必須為所有純虛擬函數提供確切的定義。
6.?
根據一般規則,凡基類定義有虛擬函數,其
destructor
應聲明為
virtual
。但
Stanley B.Lippman
并不建議在這個基類中將其
destructor
聲明為
pure virtual
,而是提供空白定義:
inline baseclass::~baseclass(){};
7.?
對于
public inheritance
,繼承而來的
public
成員和
protected
成員,無論在繼承體系中的深度如何,都可視為派生類自身擁有的成員。
8.?
每當派生類有某個
member
與其基類的
member
同名時,便會遮蔽住基類的那份
member
,若要在派生類中使用繼承而來的那份
member
,必須使用
class scope
運算符加以修飾。
9.?
不可為抽象基類定義任何對象,它們扮演的角色是每個派生類的
subobject
,基于此點,一般將抽象基類的
constructor
聲明為
protected
而非
public
。
10.?????????????
派生類之
constructor
,不僅必須為派生類之
data members
進行初始化操作,還需為其基類之
data members
提供適當的值。
copy constructor
和
copy assignment operator
的情形也一樣,唯一棘手的是,必須明白調用基類的
copy assignment operator
:
base::operator = (rhs);
11.?????????????
改寫基類提供的虛擬函數,派生類提供的定義其函數型別必須完全符合基類所聲明的函數原型,包括參數列、返回型別、常量型
const-ness
。但是,對于“返回型別”有個例外:當基類的虛擬函數返回某個基類形式(通常是
pointer
或
reference
)時,派生類中的同名函數可以返回該基類所派生出來的型別。
12.?????????????
在兩種情況下,虛擬函數機制不會出現預期行為:
1
)在基類的
constructor
和
destructor
內;
2
)使用基類的對象而非對象的
pointer
或
reference
。
13.?????????????
typeid
運算符是
RTTI
的一部分,可以用它來查詢多態化的
class pointer
或
class reference
,獲得其所指對象的實際型別。
typeid
運算符會返回一個
type_info
對象,其中存儲著與型別相關的種種信息。
#include<typeinfo>
完成日期:
2002-6-19
異常處理
?? Exception Handling
1.?
初學者常犯的錯誤:將
C++
異常和
segmentation fault
或是
bus error
這類硬件異常混淆在一起。
2.?
在異常處理機制終結某個函數之前,
C++
保證函數中的所有局部對象的
destructor
都會被調用。
3.?
auto_ptr
是標準程序庫提供的
class template
,它會自動
delete
通過
new
表達式配置的對象。
auto_ptr
將
dereference
運算符和
arrow
運算符予以重載,使得我們可以像使用一般指針一樣使用
auto_ptr
對象。
#include <memory>
4.?
如果
new
表達式無法從程序的自由空間
free store
配置到足夠的內存,它會拋出
bad_alloc
異常對象。如果要壓抑不讓
bad_alloc
異常被拋出,可以這么寫:
somepointer = new (nothrow) someclass;
這樣,如果
new
動作失敗,返回值為
0
。
5.?
標準程序庫定義了一套異常類體系
exception class hierarchy
,其最根部是名為
exception
的抽象基類。
exception
聲明有一個
what()
虛擬函數,會返回一個
const char*
,用以表示被拋出異常的文字描述。
#include <exception>
6.?
ostringstream class
提供“內存內的輸出操作”,輸出到一個
string
對象上。當需要將多筆不同型別的數據格式轉化為字符串表現式時,它尤其有用。
ostringstream
提供的
str()
可以返回對應的那個
string
對象。
#include <sstream>
7.?
iostream
庫也對應提供了
istringstream class
,如果需要將非字符串數據的字符串表現式轉化為其實際型別,
istringstream
可派上用場。
8.?
string class
的轉換函數
c_str()
會返回
const char*
!