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