????????面向?qū)ο缶幊?/a>(Object Oriented Programming蜡镶,OOP,面向?qū)ο蟪绦蛟O(shè)計)是一種計算機(jī)編程架構(gòu)考抄。OOP 的一條基本原則是計算機(jī)程序是由單個能夠起到子程序作用的單元或?qū)ο蠼M合而成。
基本介紹
????????OOP: Object Oriented Programming,面向?qū)ο蟮某绦蛟O(shè)計。所謂“對象”在顯式支持面向?qū)ο蟮恼Z言中茄唐,一般是指類在內(nèi)存中裝載的實例,具有相關(guān)的成員變量和成員函數(shù)(也稱為:方法)蝇更。面向?qū)ο蟮某绦蛟O(shè)計完全不同于傳統(tǒng)的面向過程程序設(shè)計沪编,它大大地降低了軟件開發(fā)的難度,使編程就像搭積木一樣簡單年扩,是當(dāng)今電腦編程的一股勢不可擋的潮流蚁廓。
????OOP 達(dá)到了軟件工程的三個主要目標(biāo):重用性、靈活性和擴(kuò)展性厨幻。為了實現(xiàn)整體運算相嵌,每個對象都能夠接收信息、處理數(shù)據(jù)和向其它對象發(fā)送信息况脆。OOP 主要有以下的概念和組件:
????????組件 - 數(shù)據(jù)和功能一起在運行著的計算機(jī)程序中形成的單元饭宾,組件在 OOP 計算機(jī)程序中是模塊和結(jié)構(gòu)化的基礎(chǔ)。
????????抽象性 - 程序有能力忽略正在處理中信息的某些方面格了,即對信息主要方面關(guān)注的能力看铆。
????????封裝 - 也叫做信息封裝:確保組件不會以不可預(yù)期的方式改變其它組件的內(nèi)部狀態(tài);只有在那些提供了內(nèi)部狀態(tài)改變方法的組件中盛末,才可以訪問其內(nèi)部狀態(tài)弹惦。每類組件都提供了一個與其它組件聯(lián)系的接口,并規(guī)定了其它組件進(jìn)行調(diào)用的方法悄但。
多態(tài)性?- 組件的引用和類集會涉及到其它許多不同類型的組件肤频,而且引用組件所產(chǎn)生的結(jié)果依據(jù)實際調(diào)用的類型。
繼承性 - 允許在現(xiàn)存的組件基礎(chǔ)上創(chuàng)建子類組件算墨,這統(tǒng)一并增強(qiáng)了多態(tài)性和封裝性宵荒。典型地來說就是用類來對組件進(jìn)行分組,而且還可以定義新類為現(xiàn)存的類的擴(kuò)展,這樣就可以將類組織成樹形或網(wǎng)狀結(jié)構(gòu)报咳,這體現(xiàn)了動作的通用性侠讯。
????????由于抽象性、封裝性暑刃、重用性以及便于使用等方面的原因厢漩,以組件為基礎(chǔ)的編程在腳本語言中已經(jīng)變得特別流行。Python 和 Ruby 是最近才出現(xiàn)的語言岩臣,在開發(fā)時完全采用了 OOP 的思想溜嗜,而流行的 Perl 腳本語言從版本5開始也慢慢地加入了新的面向?qū)ο?/a>的功能組件。用組件代替“現(xiàn)實”上的實體成為 JavaScript(ECMAScript) 得以流行的原因架谎,有論證表明對組件進(jìn)行適當(dāng)?shù)慕M合就可以在英特網(wǎng)上代替 HTML 和 XML 的文檔對象模型(DOM)炸宵。
OOP思想
????????面向?qū)ο缶幊?/a>技術(shù)的關(guān)鍵性觀念是它將數(shù)據(jù)及對數(shù)據(jù)的操作行為放在一起,作為一個相互依存谷扣、不可分割的整體——對象土全。對于相同類型的對象進(jìn)行分類、抽象后会涎,得出共同的特征而形成了類裹匙。面向?qū)ο缶幊叹褪嵌x這些類。類是描述相同類型的對象集合末秃。類定義好之后將作為數(shù)據(jù)類型用于創(chuàng)建類的對象概页。程序的執(zhí)行表現(xiàn)為一組對象之間的交互通信。對象之間通過公共接口進(jìn)行通信练慕,從而完成系統(tǒng)功能惰匙。類中聲明的public成員組成了對象的對外公共接口。?[1]?簡單來說就是以功能為解決問題的中心贺待。
基本思想
????????OOP的許多原始思想都來之于Simula語言徽曲,并在Smalltalk語言的完善和標(biāo)準(zhǔn)化過程中得到更多的擴(kuò)展和對以前的思想的重新注解零截◆锶可以說OO思想和OOPL幾乎是同步發(fā)展相互促進(jìn)的。與函數(shù)式程序設(shè)計(functional-programming)和邏輯式程序設(shè)計(logic-programming)所代表的接近于機(jī)器的實際計算模型所不同的是涧衙,OOP幾乎沒有引入精確的數(shù)學(xué)描敘哪工,而是傾向于建立一個對象模型,它能夠近似的反映應(yīng)用領(lǐng)域內(nèi)的實體之間的關(guān)系弧哎,其本質(zhì)是更接近于一種人類認(rèn)知事物所采用的哲學(xué)觀的計算模型雁比。由此,導(dǎo)致了一個自然的話題撤嫩,那就是OOP到底是什么偎捎?[D&T 1988][B.S 1991] .。在OOP中,對象作為計算主體茴她,擁有自己的名稱寻拂,狀態(tài)以及接受外界消息的接口。在對象模型中丈牢,產(chǎn)生新對象祭钉,舊對象銷毀雹锣,發(fā)送消息威恼,響應(yīng)消息就構(gòu)成OOP計算模型的根本。
????????對象的產(chǎn)生有兩種基本方式央拖。一種是以原型(prototype)對象為基礎(chǔ)產(chǎn)生新的對象申尼。一種是以類(class)為基礎(chǔ)產(chǎn)生新對象垮卓。原型的概念已經(jīng)在認(rèn)知心理學(xué)中被用來解釋概念學(xué)習(xí)的遞增特性,原型模型本身就是企圖通過提供一個有代表性的對象為基礎(chǔ)來產(chǎn)生各種新的對象晶姊,并由此繼續(xù)產(chǎn)生更符合實際應(yīng)用的對象扒接。而原型-委托也是OOP中的對象抽象,代碼共享機(jī)制中的一種们衙。一個類提供了一個或者多個對象的通用性描述钾怔。從形式化的觀點看,類與類型有關(guān)蒙挑,因此一個類相當(dāng)于是從該類中產(chǎn)生的實例的集合宗侦。而這樣的觀點也會帶來一些矛盾,比較典型的就是在繼承體系下忆蚀,子集(子類)對象和父集(父類)對象之間的行為相融性可能很難達(dá)到矾利,這也就是OOP中常被引用的---子類型(subtype)不等于子類(subclass)[Budd 2002]。而在一種所有皆對象的世界觀背景下馋袜,在類模型基礎(chǔ)上還誕生出了一種擁有元類(metaclass)的新對象模型男旗。即類本身也是一種其他類的對象。以上三種根本不同的觀點各自定義了三種基于類(class-based),基于原型(prototype-based)和基于元類(metaclass-based)的對象模型欣鳖。而這三種對象模型也就導(dǎo)致了許多不同的程序設(shè)計語言(如果我們暫時把靜態(tài)與動態(tài)的差別放在一邊)察皇。是的,我們經(jīng)常接觸的C++,Java都是使用基于類的對象模型泽台,但除此之外還有很多我們所沒有接觸的OOPL采用了完全不一樣的對象模型什荣,他們是在用另外一種觀點詮釋OOP的內(nèi)涵。
????????什么是oop的基本思想呢怀酷?把組件的實現(xiàn)和接口分開稻爬,并且讓組件具有多態(tài)性。不過蜕依,兩者還是有根本的不同桅锄。oop強(qiáng)調(diào)在程序構(gòu)造中語言要素的語法琉雳。你必須得繼承,使用類友瘤,使用對象咐吼,對象傳遞消息。不關(guān)心你繼承或是不繼承商佑,它的開端是分析產(chǎn)品的分類锯茄,有些什么種類,他們的行為如何茶没。就是說肌幽,兩件東西相等意味著什么?怎樣正確地定義相等操作抓半?不單單是相等操作那么簡單喂急,你往深處分析就會發(fā)現(xiàn)“相等”這個一般觀念意味著兩個對象部分,或者至少基本部分是相等的笛求,據(jù)此我們就可以有一個通用的相等操作廊移。再說對象的種類。假設(shè)存在一個順序序列和一組對于順序序列的操作探入。那么這些操作的語義是什么狡孔?從復(fù)雜度權(quán)衡的角度看,我們應(yīng)該向用戶提供什么樣的順序序列蜂嗽?該種序列上存在那些操作苗膝?那種排序是我們需要的?只有對這些組件的概念型分類搞清楚了植旧,我們才能提到實現(xiàn)的問題:使用模板辱揭、繼承還是宏?使用什么語言和技術(shù)病附?gp的基本觀點是把抽象的軟件組件和它們的行為用標(biāo)準(zhǔn)的分類學(xué)分類问窃,出發(fā)點就是要建造真實的、高效的和不取決于語言的算法和數(shù)據(jù)結(jié)構(gòu)完沪。當(dāng)然最終的載體還是語言域庇,沒有語言沒法編程。stl使用c++丽焊,你也可以用ada來實現(xiàn)较剃,用其他的語言來實現(xiàn)也行咕别,結(jié)果會有所不同技健,但基本的東西是一樣的。到處都要用到二分查找和排序惰拱,而這就是人們正在做的雌贱。對于容器的語義啊送,不同的語言會帶來輕微的不同。但是基本的區(qū)別很清楚是gp所依存的語義欣孤,以及語義分解馋没。例如,我們決定需要一個組件swap降传,然后指出這個組件在不同的語言中如果工作篷朵。顯然重點是語義以及語義分類。而oop所強(qiáng)調(diào)的(我認(rèn)為是過分強(qiáng)調(diào)的)是清楚的定義類之間的層次關(guān)系婆排。oop告訴了你如何建立層次關(guān)系声旺,卻沒有告訴你這些關(guān)系的實質(zhì)。
(這段不太好理解段只,有一些術(shù)語可能要過一段時間才會有合適的中文翻譯——譯者)
????????面向?qū)ο?/a>的編程方法OOP是九十年代才流行的一種軟件編程方法腮猖。它強(qiáng)調(diào)對象的“抽象”、“封裝”赞枕、“繼承”澈缺、“多態(tài)”。我們講程序設(shè)計是由“數(shù)據(jù)結(jié)構(gòu)”+“算法”組成的炕婶。從宏觀的角度講姐赡,OOP下的對象是以編程為中心的,是面向程序的對象柠掂。
特征
1.1面向?qū)ο蟪绦蛟O(shè)計的特征:
1) 封裝
2)?繼承
3)?多態(tài)
4)抽象
1.2類與數(shù)據(jù)封裝
1.2.1什么是類雏吭?
????????簡單的說,類就是一種用戶定義的數(shù)據(jù)類型陪踩,跟結(jié)構(gòu)類似杖们;并且,類具有自己的成員變量和成員函數(shù)(方法)肩狂,通過它們可以對類自身進(jìn)行操作摘完。如:汽車可以看作是發(fā)動機(jī)、車輪傻谁、座椅等諸如此類的集合孝治。也可以從功能的角度來研究,譬如审磁,能移動谈飒,加速,減速态蒂,剎車等杭措。
例如:
class CMyClass1
{
protected:
CMyClass1();
public:
virtual ~ CMyClass1();
}
1.2.2?封裝(encapsulation)
定義:指能夠把一個實體的信息、功能钾恢、響應(yīng)都裝入一個單獨的對象中的特性手素。封裝的優(yōu)點如下:
1) 封裝允許類的客戶不必關(guān)心類的工作機(jī)理就可以使用它鸳址。就象駕駛員不必了解發(fā)動機(jī)的工作原理就可以駕駛汽車一樣,類的客戶在使用一個類時也不必了解它是如何工作的泉懦,而只需了解它的功能即可稿黍。
2) 所有對數(shù)據(jù)的訪問和操作都必須通過特定的方法,否則便無法使用崩哩,從而達(dá)到數(shù)據(jù)隱藏的目的巡球。
1.2.3?對象
????????對象就是類的實例。類與對象的關(guān)系就如類型和變量的關(guān)系邓嘹,所有對類的操作都必須通過對象來實現(xiàn)辕漂。當(dāng)一個類定義了多個對象時,每個對象擁有各自的成員數(shù)據(jù)吴超。
1.2.4?類的三種成員類型
1) 私有成員(private):缺省情況下钉嘹,一個類中的所有成員都是私有的。私有成員只能被類本身的成員函數(shù)訪問鲸阻。能夠被繼承但是被繼承的私有成員不能夠使用跋涣。
2) 公有成員(public):公有成員可以被類成員函數(shù)和外部函數(shù)使用。
3) 保護(hù)成員(protected):類的保護(hù)成員能被類及其派生類的成員函數(shù)和友元函數(shù)使用鸟悴,具有繼承性陈辱。
1.2.5?構(gòu)造函數(shù)與析構(gòu)函數(shù)
1)構(gòu)造函數(shù)
a. 是特殊的成員函數(shù);在創(chuàng)建對象時首先由系統(tǒng)自動調(diào)用细诸。它的作用是為新創(chuàng)建的對象分配空間沛贪,或為該對象的成員變量賦值等;
b. 構(gòu)造函數(shù)名必須與其類名稱完全相同震贵,并且不允許有返回值利赋。
2)析構(gòu)函數(shù)
a. 析構(gòu)函數(shù)是構(gòu)造函數(shù)的逆操作;
b. 析構(gòu)函數(shù)在類名之前加~來命名猩系,它不允許有返回值媚送,也不允許帶參數(shù),并且一個類只能有一個析構(gòu)函數(shù)寇甸。
1.3繼承
1.3.1?傳統(tǒng)程序設(shè)計的缺點:
增加功能對程序所作的修改工作量非常大塘偎。
1.3.2?繼承的優(yōu)點:
????????繼承的方法允許在不改動原程序的基礎(chǔ)上對其進(jìn)行擴(kuò)充,這樣使得原功能得以保存拿霉,而新功能也得以擴(kuò)展吟秩。這有利于減少重復(fù)編碼,提高軟件的開發(fā)效率绽淘。
1.3.3?基類與派生類
1)一個類可以繼承其它類的成員涵防,被繼承的類叫基類或父類;繼承類叫派生類或子類
2)派生類不但擁有自己的成員變量和成員函數(shù)收恢,還擁有父類的成員變量和成員函數(shù)武学。
1.3.4?類的保護(hù)成員(protected)
????????前面介紹了類的私有成員只能被類的成員函數(shù)和友員函數(shù)使用;類的保護(hù)成員能被類及其派生類的成員函數(shù)和友員函數(shù)使用伦意。也就是說火窒,類的保護(hù)成員具有繼承性,而類的私有成員不具有繼承性驮肉。
1.3.5?公用基類和私有基類
1)公用基類中的所有public成員在派生類中仍是public成員熏矿,所有protected成員在派生類中仍是protected成員。
2)私有基類中的public成員和protected成員在派生類中均變成private成員离钝。
1.3.6?多重繼承
1)多重繼承的定義方法
例子:
class A
{
…
public:
int i;
void func1();
…
};
class B
{
…
public:
int i;
void func1();
…
};
class C: public A,B
{
…
void Show()
…
};
缺省情況下基類被定義為 private票编;因此基類B為私有基類。
2)繼承的不確定性
例子:
class C:public A,B
{
…
void Show()
{
j = i*i;
func1();
}
…
};
????????由于基類A和B中同時擁有數(shù)據(jù)成員i和成員函數(shù)func1卵渴,類C引用基類的成員時慧域,系統(tǒng)無法分辨是調(diào)用哪一基類的成員而發(fā)生錯誤;
3)解決多重繼承的不確定性:
使用域操作符指明要調(diào)用的基類浪读,即可解決不確定性問題昔榴。
class C:public A,B
{
…
int j;
void Show()
{
j = A::i*B::i;
A::func1();
}
…
};
1.3.7?多層繼承
????????定義:所謂多層繼承指的是從一個類派生出另一個類,然后以派生類作為基類碘橘,派生出另一個類互订,直到最后生成的派生類滿足需要為止(見MSDN中的Hierarchy Chart)。
1.3.8?派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)
在繼承關(guān)系下痘拆,派生類的構(gòu)造函數(shù)負(fù)責(zé)調(diào)用基類的構(gòu)造函數(shù)來設(shè)置基類數(shù)據(jù)成員值仰禽。
例:
class base
{//基類
…
public:
int i;
base(int j)
{//構(gòu)造函數(shù)
i = j;
}
…
};
class derived:public base
{//派生類
…
public:
double f;
derived(int, double);
…
};
derived::derived(int k, double l):base(k)
{//派生類構(gòu)造函數(shù)
…
f = l;
…
}
1.3.9?構(gòu)造函數(shù)的調(diào)用順序
1) 在定義派生類對象時,系統(tǒng)首先調(diào)用基類的構(gòu)造函數(shù)纺蛆,然后調(diào)用派生類的構(gòu)造函數(shù)吐葵;在上例中,derived類首先調(diào)用base類的構(gòu)造函數(shù)桥氏,然后調(diào)用自身的構(gòu)造函數(shù)折联。
2)?析構(gòu)函數(shù)的調(diào)用順序與構(gòu)造函數(shù)的調(diào)用順序相反。
1.4重載
1.4.1函數(shù)重載
1)如果函數(shù)有相同的名稱和返回值识颊,而有不同的參數(shù)個數(shù)或參數(shù)類型诚镰,則這些函數(shù)就是重載函數(shù)。
2)派生類繼承了基類的某一函數(shù)祥款,并且又自定義了一個同名函數(shù)清笨,有相同的返回值,不同的參數(shù)類型或參數(shù)個數(shù)刃跛。這種情況不屬于重載抠艾。因為它們屬于不同的域。
3)例:
class base
{
…
void func(int i)
{
…
}
void func(double f)
{
…
}
void func(double f, long q)
{
…
}
…
};
1.4.2?操作符重載
重載操作符的定義:返回值類型 operator op (參數(shù)表)桨昙;其中检号,op為重載操作符腌歉,它必須是VC++中所定義的運算符。然后像定義函數(shù)一樣定義重載操作符函數(shù)齐苛。
例子:
class person
{
…
int age;
void operator ++();
…
};
void person::operator++()
{
age++;
}
1.5虛擬函數(shù)與多態(tài)性
多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計的精髓之所在翘盖,也是C++中最難理解和掌握的部分。在C++中凹蜂,多態(tài)性是建立在虛擬函數(shù)基礎(chǔ)上的馍驯,虛擬函數(shù)的使用使類的成員函數(shù)表現(xiàn)出多態(tài)性。
1.5.1虛擬函數(shù)
1)函數(shù)的定義:在定義類時在其成員函數(shù)前加上關(guān)鍵字virtual玛痊;
2)如果基類中成員函數(shù)定義為虛函數(shù)汰瘫,則派生類中與其定義完全相同的成員函數(shù),編譯器自動將其視為虛函數(shù)擂煞;
3)只有類的成員函數(shù)才能定義為虛函數(shù)混弥。
4)虛擬成員函數(shù)的存取要看首次定義它的類中,該函數(shù)是public還是private对省。
例:
class Insect
{
…
virtual bool CanFly();
…
};
bool Insect :: CanFly()
{
return FALSE;
}
class Butterfly:public Insect
{
…
bool CanFly();
…
};
bool Butterfly :: CanFly()
{
return TRUE;
}
1.5.2?虛函數(shù)的調(diào)用
1) 根據(jù)對象的不同而去調(diào)用不同類的虛擬函數(shù)
2) 可以使用基類對象調(diào)用派生類對象剑逃,即將派生類對象或指針賦值給基類對象或指針。
3) 反方向的賦值(將基類的對象或指針賦給派生類的對象或指針)是危險的官辽。
例:
bool rtn;
Insect inc1,*pInc;
Butterfly btfly;
pInc = &inc1; //pInc指針指向Insect對象
rtn = pInc->CanFly(); //返回FALSE
pInc = &btfly; //pInc指針指向Butterfly對象
rtn = pInc->CanFly(); //返回TRUE
1.5.3?虛擬函數(shù)與重載函數(shù)的區(qū)別
1)形式上蛹磺,重載函數(shù)要求有相同的返回值類型和函數(shù)名,并有不同的參數(shù)序列同仆;而虛擬函數(shù)要求三者完全相同萤捆。
2)重載函數(shù)可以是成員函數(shù)或非成員函數(shù);而虛擬函數(shù)必須是成員函數(shù)俗批。
3)調(diào)用方法上俗或,重載函數(shù)根據(jù)所傳遞的參數(shù)序列的差別作為調(diào)用的依據(jù);而虛擬函數(shù)則根據(jù)調(diào)用對象的不同而去調(diào)用不同類的函數(shù)岁忘。
4)虛擬函數(shù)在運行時表現(xiàn)出多態(tài)功能辛慰;而重載函數(shù)不具有這一功能。
1.5.4純虛函數(shù)
定義:virtual type funcname(parameter)=0;
????????C++中有時設(shè)計基類就是為了被繼承干像,而基類中的虛擬函數(shù)不做任何工作帅腌,這種情況下可以將基類中的虛擬函數(shù)定義為純虛函數(shù)。包含純虛函數(shù)的類叫抽象類麻汰。抽象類不能定義對象速客,但可以定義指向它的指針。
歷史
????????面向?qū)ο蠹夹g(shù)最初是從面向?qū)ο蟮某绦蛟O(shè)計開始的五鲫,它的出現(xiàn)以60年代simula語言為標(biāo)志溺职。80年代中后期,面向?qū)ο蟪绦蛟O(shè)計逐漸成熟,被計算機(jī)界理解和接受浪耘,人們又開始進(jìn)一步考慮面向?qū)ο蟮拈_發(fā)問題乱灵。這就是九十年代以Microsoft Visual系列OOP軟件的流行的背景。
????????傳統(tǒng)的結(jié)構(gòu)化分析與設(shè)計開發(fā)方法是一個線性過程七冲,因此痛倚,傳統(tǒng)的結(jié)構(gòu)化分析與設(shè)計方法要求現(xiàn)實系統(tǒng)的業(yè)務(wù)管理規(guī)范,處理數(shù)據(jù)齊全癞埠,用戶能全面完整地其業(yè)務(wù)需求状原。
????????傳統(tǒng)的軟件結(jié)構(gòu)和設(shè)計方法難以適應(yīng)軟件生產(chǎn)自動化的要求聋呢,因為它以過程為中心進(jìn)行功能組合苗踪,軟件的擴(kuò)充和復(fù)用能力很差。
????????對象是對現(xiàn)實世界實體的模擬削锰,因面能更容易地理解需求通铲,即使用戶和分析者之間具有不同的教育背景和工作特點,也可很好地溝通器贩。
區(qū)別面向?qū)ο?/a>的開發(fā)和傳統(tǒng)過程的開發(fā)的要素有:對象識別和抽象颅夺、封裝、多態(tài)性和繼承蛹稍。
????????對象(Object)是一個現(xiàn)實實體的抽象吧黄,由現(xiàn)實實體的過程或信息牲來定義。一個對象可被認(rèn)為是一個把數(shù)據(jù)(屬性)和程序(方法)封裝在一起的實體唆姐,這個程序產(chǎn)生該對象的動作或?qū)λ邮艿降耐饨缧盘柕姆磻?yīng)拗慨。這些對象操作有時稱為方法。對象是個動態(tài)的概念,其中的屬性反映了對象當(dāng)前的狀態(tài)奉芦。
????????類(Class)用來描述具有相同的屬性和方法的對象的集合赵抢。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例声功。
????????由上分析不難看出烦却,盡管OOP技術(shù)更看中用戶的對象模型,但其目的都是以編程為目的的先巴,而不是以用戶的信息為中心的其爵,總想把用戶的信息納入到某個用戶不感興趣的“程序?qū)ο蟆敝小?/p>
優(yōu)缺點
·???????? OOP 的優(yōu)點:使人們的編程與實際的世界更加接近,所有的對象被賦予屬性和方法伸蚯,結(jié)果編程就更加富有人性化醋闭。
·???????? OOP 的也有缺點,就 C++ 而言朝卒,由于面向更高的邏輯抽象層证逻,使得 C++ 在實現(xiàn)的時候,不得不做出性能上面的犧牲,有時候甚至是致命的 ( 所有對象的屬性都經(jīng)過內(nèi)置多重指針的間接引用是其性能損失的主要原因之一囚企;不過丈咐,筆者的局限性在于未使用過 VC++ 外的面向?qū)ο笳Z言,所以不是十分肯定龙宏,哈哈棵逊,有人笑出來了… )。
????????在計算機(jī)速度飛速發(fā)展的今天银酗,你可能會說辆影,一丁點的性能犧牲沒什么大不了。是的黍特,從面向?qū)ο蟮慕嵌韧芗ィ沟木幊痰慕Y(jié)構(gòu)更加清晰完整,數(shù)據(jù)更加獨立和易于管理灭衷,性能的犧牲可以帶來這么多的好處次慢,沒有理由不做穩(wěn)賺的生意吧?
????????不過翔曲,在某些對速度要求極高特殊場合迫像,例如你做的是電信的交換系統(tǒng),每秒鐘有超過百萬的人同時進(jìn)行電話交換瞳遍,如果闻妓,每一個數(shù)據(jù)交換過程都是一個對象,那么總的性能損失將是天文數(shù)字B有怠由缆!
????????或者這個例子不夠貼身,再舉個例子吧份蝴。假如你受聘于一個游戲設(shè)計公司犁功,老板希望做出來的游戲可以更多的兼顧到更多的電腦使用者,游戲每秒鐘的運行的幀可以更多婚夫,子彈和爆炸物可以更多浸卦、更華麗。那么案糙,你會發(fā)現(xiàn)使用 C++ 會使你的程序變得笨拙限嫌,無法滿足你的需求,除非你非得要你的游戲運行于奔騰四的機(jī)器上 ( 如果不是时捌,而你又堅持用 C++ 的對象編程怒医,那么請減少主角的槍的威力吧 )。
????????如果你是冥頑不靈的人奢讨,你說不相信 OOP 會有性能上的損失稚叹,那么,我記得曾看到在 CSDN 上關(guān)于 VB 和 VC 執(zhí)行效率的討論的文章,講述的就是使用了 MFC 以后扒袖,執(zhí)行效率甚至低于 VB 開發(fā)出來的東西塞茅。請各位驗證一下:如果使用的是純粹的 C 語言語法的話,那么一定會比在 VB 編出來的東西要快很多 ( GetTickCount 函數(shù)可以查閱 MSDN ,如果想更加精確一些季率,可以使用 QueryPerformanceCounter 函數(shù) )野瘦。
未來
(撰文/Bjarne Stroustrup & Tim Lindholm 編譯/孟巖)
在未來三年,程序員編寫代碼的方式會發(fā)生哪些變化飒泻?
????????Stroustrup: 在C++中鞭光,假如沒有合適的庫在背后支撐,完成任何重要的工作都可能是很復(fù)雜的泞遗。而一旦有了合適的庫惰许,任何東西都可以被我們操控于股掌之間。因此刹孔,構(gòu)造和使用程序庫的重要性與日俱增啡省。這也暗示我們娜睛,泛型程序設(shè)計(generic programming)將會越來越多地被運用髓霞。只有通過GP,我們才能確保庫的通用性和高效率畦戒。我還預(yù)期在分布式計算和“組件(components)”應(yīng)用領(lǐng)域會出現(xiàn)喜人的增長方库。就大部分程序員而言,通過使用方便適用的程序庫障斋,這些開發(fā)工作會變得簡單明了纵潦。
????????現(xiàn)在有一個趨勢,編譯器廠商試圖把其特有的“對象模型”和圖形界面(GUI)細(xì)節(jié)推銷給用戶垃环。比如微軟的COM和Inprise的類屬性“properties”邀层。對于用戶來說,這既不必要遂庄,也不情愿寥院。我所希望看到的程序庫,應(yīng)該是用標(biāo)準(zhǔn)C++打造涛目,界面靈活秸谢,值得信賴的程序庫。通常霹肝,這些界面應(yīng)該是平臺無關(guān)的估蹄。C++的表達(dá)能力極強(qiáng),即使不使用大量的宏沫换,也應(yīng)該足以達(dá)成這一要求臭蚁。就算有些地方無法百分之百的遵守這一原則,也應(yīng)該將對于平臺和廠家的依賴性限制起來。這個目標(biāo)的完成情況垮兑,可以反映軟件工具產(chǎn)業(yè)對于應(yīng)用程序開發(fā)行業(yè)的關(guān)注程度炭晒。我懷疑目前對于那些獨立的、跨平臺廠商來說甥角,并不存在相應(yīng)的市場网严。如果能夠建立這樣的市場,也許能夠促進(jìn)廠商們?yōu)榭蛻糇龀觥罢嬲杏玫摹碑a(chǎn)品嗤无。
????????Lindholm: 對于編寫代碼的開發(fā)者來說震束,主要的驅(qū)動力量仍將是兩個:網(wǎng)絡(luò)和分布式——也就是設(shè)計和開發(fā)非單機(jī)軟件的需求。大部分的應(yīng)用程序?qū)⒉粫枪铝懔愕剡\行在單一設(shè)備上当犯,而是運用了類似EJB和JSP之類技術(shù)的垢村,平臺無關(guān)的分布式程序。程序員們將不得不面對分布式計算的重重險阻嚎卫。這將對許多程序員所依賴的設(shè)計模式嘉栓、技術(shù)和直覺構(gòu)成嚴(yán)峻的挑戰(zhàn)缭付。這是選擇編程語言之前必須認(rèn)識到的啰挪,盡管不同語言的設(shè)計特性可能促進(jìn)或者阻礙這一轉(zhuǎn)化。
????????在網(wǎng)絡(luò)應(yīng)用的增長中踱蛀,一個很重要的部分是小型移動設(shè)備和特殊Internet設(shè)備的爆炸性增長奠支。這些設(shè)備各有各的操作系統(tǒng)馋辈,或者只在某種特定的設(shè)備領(lǐng)域內(nèi)有共同的操作系統(tǒng)。我們現(xiàn)在還可以一一列舉出這些設(shè)備——家庭接入設(shè)備倍谜、蜂窩電話迈螟、電子報紙、PDA尔崔、自動網(wǎng)絡(luò)設(shè)備等等答毫。但是這些設(shè)備領(lǐng)域的數(shù)量和深入程度將會很快變得難以估量。我們都知道這個市場大得驚人季春,PC的興起與之相比不過小菜一碟洗搂。因此在這些設(shè)備的應(yīng)用程序市場上,競爭將會相當(dāng)殘酷鹤盒。獲勝的重要手段之一蚕脏,就是盡快進(jìn)入市場。開發(fā)人員需要優(yōu)秀的工具侦锯,迅速高效地撰寫和調(diào)試他們的軟件驼鞭。平臺無關(guān)性也是制勝秘訣之一,它使得程序員能夠開發(fā)出支持多種設(shè)備平臺的軟件尺碰。
????????我預(yù)期的另一個變化是挣棕,我們對于代碼(Java)和數(shù)據(jù)(XML)協(xié)同型應(yīng)用程序的開發(fā)能力將會不斷提高译隘。這種協(xié)同是開發(fā)強(qiáng)大應(yīng)用程序的核心目標(biāo)之一。我們從XML的迅速流行和ebXML規(guī)范的進(jìn)展中洛心,已經(jīng)看到了這個趨勢固耘。ebXML是一個針對電子商務(wù)和國際貿(mào)易的,基于XML的開放式基礎(chǔ)構(gòu)架词身,由聯(lián)合國貿(mào)易促進(jìn)和電子商務(wù)中心(UN/CEFACT)與結(jié)構(gòu)性信息標(biāo)準(zhǔn)推進(jìn)組織(OASIS)共同開發(fā)厅目。
我們能否期望出現(xiàn)一個真正的面向組件(component-oriented)的語言?它的創(chuàng)造者會是誰呢法严?
????????Stroustrup: 我懷疑损敷,這個領(lǐng)域中之所以缺乏成果,正是因為人們——主要是那些非程序員們——對“組件”這個意義含糊的字眼寄予了太多的期望深啤。這些人士夢想拗馒,有朝一日,組件會以某種方式把程序員趕出歷史舞臺溯街。以后那些稱職的“設(shè)計員”只需利用預(yù)先調(diào)整好的組件诱桂,把鼠標(biāo)拖一拖放一放,就把系統(tǒng)組合出來呈昔。對于軟件工具廠商來說挥等,這種想法還有另一層意義,他們認(rèn)為韩肝,到時候只有他們才保留有必要的技術(shù)触菜,有能力編寫這樣的組件九榔。
????????這種想法有一個最基本的謬誤:這種組件很難獲得廣泛歡迎哀峻。一個單獨的組件或框架(framework),如果能夠滿足一個應(yīng)用程序或者一個產(chǎn)業(yè)領(lǐng)域?qū)λ岢龅拇蟛糠忠蟮脑捳懿矗瑢τ谄渲圃煺邅碚f就是劃算的產(chǎn)品剩蟀,而且技術(shù)上也不是很困難∏型可是該產(chǎn)業(yè)內(nèi)的幾個競爭者很快就會發(fā)現(xiàn)育特,如果所有人都采用這些組件,那么彼此之間的產(chǎn)品就會變得天下大同先朦,沒什么區(qū)別缰冤,他們將淪為簡單的辦事員,主要利潤都將鉆進(jìn)那些組件/框架供應(yīng)商的腰包里喳魏!
小“組件”很有用棉浸,不過產(chǎn)生不了預(yù)期的杠桿效應(yīng)。中型的刺彩、更通用的組件非常有用迷郑,但是構(gòu)造時需要非同尋常的彈性枝恋。
????????在C++中,我們綜合運用不同共享形式的類體系(class hierarchies)嗡害,以及使用templates精心打造的接口焚碌,在這方面取得了一定的進(jìn)展。我期待在這個領(lǐng)域取得一些有趣和有用的成果霸妹,不過我認(rèn)為這種成果很可能是一種新的C++程序設(shè)計風(fēng)格十电,而不是一種新的語言。
????????Lindholm: 編寫面向組件的應(yīng)用程序叹螟,好像更多的是個投資摆出、設(shè)計和程序員管理方面的問題,而不是一個編程語言問題首妖。當(dāng)然某些語言在這方面具有先天優(yōu)勢偎漫,不過如果說有什么魔術(shù)般的新語言能夠大大簡化組件的編寫難度,那純粹是一種誤導(dǎo)有缆。
微軟已經(jīng)將全部賭注押在C#上象踊,其他語言何去何從?
????????Stroustrup: C++在下一個十年里仍然將是一種主流語言棚壁。面對新的挑戰(zhàn)杯矩,它會奮起應(yīng)對。一個創(chuàng)造了那么多出色系統(tǒng)的語言袖外,絕不會“坐視落花流水春去也”史隆。
????????我希望微軟認(rèn)識到,它在C++(我指的是ISO標(biāo)準(zhǔn)C++)上有著巨大的利益曼验,C++是它與IT世界內(nèi)其他人之間的一座橋梁泌射,是構(gòu)造大型系統(tǒng)和嵌入式系統(tǒng)的有效工具,也是滿足高性能需求的利器鬓照。其他語言熔酷,似乎更注重那些四平八穩(wěn)的商用程序。
競爭
C#會不會獲得廣泛的接受豺裆,并且擠掉其他的語言拒秘?
????????Lindholm: 通常,一種語言既不會從別的語言那里獲利臭猜,也不會被擠掉躺酒。那些堅定的Fortran程序員不還用著Fortran嗎?對于個人來說蔑歌,語言的選擇當(dāng)然因時而異羹应,但就整體而言,語言的種類只會遞增丐膝,也就是說量愧,它們之間的關(guān)系是“有你有我”而不是“有你沒我”钾菊。
????????對于一個新語言的接受程度,往往取決于其能力所及偎肃。Java技術(shù)被迅速接受煞烫,原因是多方面的,Internet和World Wide Web接口累颂,在其他技術(shù)面前的挫折感滞详,對于Java技術(shù)發(fā)展方向的全面影響能力,都是原因紊馏。另一個重要的原因是Java獨立于廠商料饥,這意味著在兼容產(chǎn)品面前可以從容選擇。
????????C#是否會獲得廣泛接受朱监?視情況而定岸啡。總的來說赫编,那些對于平臺無關(guān)性和廠商無關(guān)性漠不關(guān)心的程序員巡蘸,可能會喜歡C#。那些跟微軟平臺捆在一起人當(dāng)然可能想要尋找VB 和VC的一個出色的替代品擂送。但是對于程序跨平臺執(zhí)行能力特別關(guān)注的程序員悦荒,將會堅守Java之類的語言。這種能力對于多重訪問設(shè)備(multiple access devices)和分布式計算模型至關(guān)重要嘹吨,而Java語言提供了一個標(biāo)準(zhǔn)的搬味、獨立于廠商運行時環(huán)境。
????????Stroustrup:C#的流行程度幾乎完全取決于微軟投入的資金多少蟀拷∨鑫常看上去C#的興起肯定會犧牲掉其他一些語言的利益,但是事實上未必如此匹厘。Java的蓬勃發(fā)展并沒有給C++帶來衰敗嘀趟。C++的應(yīng)用仍然在穩(wěn)定增長(當(dāng)然,已經(jīng)不是爆炸性的增長了)愈诚。也許其他的語言也還能獲得自己的一席之地。
不過牛隅,我實在看不出有什么必要再發(fā)明一種新的專有語言炕柔。特別是微軟,既生VB媒佣,何需C#匕累?
優(yōu)劣勢
????????Stroustrup: C++的優(yōu)點自始至終都是這么幾條:靈活、高效默伍,而且并非專有語言』逗伲現(xiàn)在ISO C++標(biāo)準(zhǔn)的出現(xiàn)衰琐,鞏固了最后一點。
????????我認(rèn)為C++的高效是它最基本的優(yōu)點炼蹦。這種高效來自于其特有的數(shù)據(jù)和計算模型羡宙,較之Java和C#,這種模型更加貼近機(jī)器掐隐。不過狗热,哪些程序才真正地渴望這么高的效率?這是個問題虑省。我認(rèn)為這類程序非常多匿刮。人們對于計算機(jī)的期望,永遠(yuǎn)都超越硬件科技的發(fā)展速度探颈。很顯然熟丸,Java和C#的設(shè)計者的想法不同,他們認(rèn)為伪节,在很多地方效率問題無關(guān)緊要虑啤。
????????C++主要的缺點,歸罪于糟糕的教育(是那些始終認(rèn)為C++是個純粹面向?qū)ο笳Z言的人架馋,和那些把C++當(dāng)成C語言變體的人導(dǎo)致了這種情況)狞山,歸罪于不同平臺上的不一致性,歸罪于不完整叉寂、不標(biāo)準(zhǔn)的編譯器實現(xiàn)萍启,歸罪于平臺無關(guān)的系統(tǒng)級程序庫的缺少。
這些問題歸于一點屏鳍,就是缺乏一個卓越的廠商勘纯,能夠滿足整個C++社區(qū)的需求,勇于投入大量的資金開發(fā)必要的程序庫钓瞭。
????????Lindholm: Java技術(shù)的成功驳遵,是因為它在合適的時間,出現(xiàn)在合適的地點山涡,而且合理地選擇了語言和計算平臺的支持目標(biāo)堤结。Java并不是在所有場合都優(yōu)于其他OOP語言,但是對于出現(xiàn)的新問題能夠解決得很出色鸭丛。它面向Internet計算環(huán)境竞穷,避免了C++中晦澀的結(jié)構(gòu),成功翻越了繼承機(jī)制的惱人問題鳞溉。垃圾收集機(jī)制顯著地提高了生產(chǎn)率瘾带,降低了復(fù)雜度。在網(wǎng)絡(luò)背景下使用虛擬機(jī)熟菲,以及有關(guān)安全性和動態(tài)加載的一系列設(shè)計選擇看政,迎合了正在出現(xiàn)的需求和愿望朴恳。這些特性使Java不僅成為現(xiàn)有程序員的新武器,而且也為新的程序員創(chuàng)造了繁榮的市場空間允蚣。
????????此外于颖,Java擁有一個標(biāo)準(zhǔn)化的、二進(jìn)制形式的類庫厉萝,提供了必要的(當(dāng)然并非充分的)平臺與廠商無關(guān)性恍飘。平臺與廠商無關(guān)性要求一項技術(shù)必須有清晰的規(guī)范,摒棄那些阻礙二進(jìn)制標(biāo)準(zhǔn)實施的特性谴垫。C++雖然有一個ISO標(biāo)準(zhǔn)章母,但其實甚至對于相同系統(tǒng)與相同指令體系的各個平臺,也提不出一個實用的翩剪、各版本兼容的二進(jìn)制標(biāo)準(zhǔn)乳怎。
????????歷史上很多使用虛擬機(jī)的語言飽受責(zé)難,是因為其不夠出色的性能問題前弯,而這要歸過于緩慢的解釋器和糟糕的垃圾收集器蚪缀。Java的早期實現(xiàn)也因為同樣的問題受到嚴(yán)厲的批評。但是自那時起恕出,業(yè)界向新的虛擬機(jī)實現(xiàn)技術(shù)投入了大量資金询枚,取得了顯著的效果,如今在大部分場合浙巫,Java的性能跟常規(guī)的靜態(tài)編譯語言相比毫不遜色金蜀。這使得程序員在獲得平臺和廠商無關(guān)性的同時,也不必付出性能上的代價的畴。
????????C++并沒有強(qiáng)制使用面向?qū)ο蠓椒?/a>渊抄,因此為了編寫出色的面向?qū)ο蟠a,就要求程序員們有相當(dāng)強(qiáng)的紀(jì)律性丧裁。很多公司就是因為這個原因放棄了C++护桦。作為語言,Java的一個突出的優(yōu)點就是強(qiáng)制面向?qū)ο?/a>方法煎娇,不允許非面向?qū)ο蟮慕Y(jié)構(gòu)二庵。
C#介于C++和Java之間,腳踏兩只船逊桦,因此既不夠安全眨猎,又失之復(fù)雜。
????????對于公司來說强经,采用新的語言要付出巨大代價。雇不到好的程序員(沒人熟悉這種新語言)寺渗,培訓(xùn)費用高得驚人匿情,學(xué)習(xí)過程中生產(chǎn)率和產(chǎn)品質(zhì)量下降兰迫,多年的經(jīng)驗隨風(fēng)消逝,等等炬称。一種語言如何克服這些障礙汁果?
????????Lindholm: 說得很對,采用新東西確實常常開銷巨大玲躯。不過問題是:這個新東西是否能夠節(jié)省更多的開支据德,或者提供巨大的改進(jìn),獲取合理的回報跷车?很多公司發(fā)現(xiàn)棘利,轉(zhuǎn)向Java技術(shù)不論在開發(fā)的后端(盡快進(jìn)入市場、快速迭代開發(fā)朽缴、維護(hù)簡單性)還是前端(跨平臺發(fā)布善玫,適用范圍從低端設(shè)備到高端服務(wù)器的技術(shù),安全性)密强,都能節(jié)省大筆的開銷茅郎。
????????對于新事物的接納,常常是在痛楚的壓力之下或渤。很大程度上系冗,這正是Java所經(jīng)歷的。Java的產(chǎn)生薪鹦,是對當(dāng)時很多系統(tǒng)的缺陷所做出的反應(yīng)掌敬。Java技術(shù)通過下面的手段減輕了開發(fā)者的痛楚:1) 顧及了網(wǎng)絡(luò)計算方面的需求,是應(yīng)運而生距芬。2) 在技術(shù)能力的抉擇上涝开,保持良好的品位,顧及了大眾的心理框仔。3) 采用適度強(qiáng)制性策略推行設(shè)計決定舀武。此外,Java技術(shù)已經(jīng)成為大學(xué)教學(xué)中的主流离斩,這同樣保證了Java開發(fā)者隊伍的不斷壯大银舱。
????????但是最重要的一點是,再沒有另一種程序設(shè)計技術(shù)跛梗,能夠像Java那樣允許程序員開發(fā)基于Internet的不同平臺之上的應(yīng)用程序寻馏。Java平臺在這方面的杰出表現(xiàn),已經(jīng)被大量的實例證明核偿。Java已經(jīng)成為Internet上的缺省應(yīng)用程序平臺诚欠,Java APIs也成為Internet應(yīng)用程序開發(fā)的天然平臺。
????????Stroustrup: 微軟和Sun把大筆的金錢扔在Java、VB和C#中轰绵,并不是因為他良心發(fā)現(xiàn)粉寞,也不是因為他們真的相信這些語言能夠帶給程序員更美好的生活,而是利益使然左腔。
????????有一個說法唧垦,認(rèn)為軟件工具廠商如果能夠把應(yīng)用程序開發(fā)者的專業(yè)技術(shù)任務(wù)負(fù)擔(dān)起來,將獲取巨大的經(jīng)濟(jì)利益液样。我對其背后的經(jīng)濟(jì)分析頗為懷疑振亮,我認(rèn)為這很難成為現(xiàn)實,特別是當(dāng)應(yīng)用程序開發(fā)者使用開放的鞭莽、標(biāo)準(zhǔn)化的工具時坊秸,他們可以有多種選擇,從而使上面的想法更加不可能撮抓。
????????多年以前妇斤,C++就已經(jīng)具有泛型能力(也就是templates和STL),有運算符重載丹拯,有枚舉類型站超?我們會不會在Java的未來版本中看到這些特性?Java是不是應(yīng)該納入這些特性呢乖酬?
????????Strousturp:從1988-89年起死相,C++就已經(jīng)有了templates。但是我們花了不少時間來了解如何最好地運用這個工具咬像,早期各廠家對于template的支持在品質(zhì)上也有很大的差異算撮。有些編譯器廠商動作遲緩,至少有一個主要的編譯器廠商(好像是指微軟县昂,微軟在Visual C++4.0才開始支持template肮柜,在此之前一直聲稱template是過于復(fù)雜而又沒什么用的技術(shù),時至今日倒彰,Visual C++對于template的支持在主流編譯器中都屬于最差的一檔——譯者注)暗中鼓勵聲名狼藉的反template宣傳审洞,直到他們自己終于學(xué)會了這項技術(shù)為止。直到今天待讳,對于template的支持在品質(zhì)上仍然有待改進(jìn)芒澜。
????????你上面提到的那些特性,我認(rèn)為Java(還有C#)應(yīng)該创淡,也肯定會逐漸引入痴晦。那些對于程序員來說最有用的語言特性和概念,將會逐漸集中琳彩,成為各家主流語言的必然之選誊酌。也就是說部凑,我認(rèn)為類似析構(gòu)函數(shù)和模板特殊化之類的機(jī)制,遠(yuǎn)遠(yuǎn)比枚舉等機(jī)制重要得多术辐。
????????Lindholm:Java技術(shù)成功的原因之一砚尽,就是很清楚哪些不該做施无。我們得多問幾個為什么:這項特性是不是必不可少辉词?增加它會帶來哪些開銷?運算符重載是C++中一項極其強(qiáng)大的特性猾骡,但是它也大大增加了C++語言的復(fù)雜度瑞躺,很多人都難以招架。Java在各種可能的權(quán)衡之中兴想,做出了明智的抉擇幢哨,找到了能力與需求之間的完美平衡點。
????????當(dāng)然嫂便,Java也會發(fā)展捞镰,而且最重要的是,現(xiàn)在是開發(fā)者們在推動發(fā)展毙替。Java增加泛型能力這件事岸售,很好地展示了Java是如何通過整個開發(fā)者社群的參與,在權(quán)衡中決定正確的平衡點厂画。關(guān)于增加泛型類型(generic types)的“Java規(guī)格申請”(Java Specification Request, JSR)已經(jīng)進(jìn)入JCP(Java Community Process)程序凸丸,而且已經(jīng)開發(fā)了很長一段時間。現(xiàn)在袱院,在JCP中屎慢,有超過80個JSRs正在討論中,這充分體現(xiàn)了整個體系對開發(fā)者的積極反饋和高度合作忽洛,這正是驅(qū)動Java平臺不斷進(jìn)化的動力腻惠。