????????面向?qū)ο缶幊?/a>(Object Oriented Programming,OOP,面向?qū)ο蟪绦蛟O(shè)計(jì))是一種計(jì)算機(jī)編程架構(gòu)。OOP 的一條基本原則是計(jì)算機(jī)程序是由單個(gè)能夠起到子程序作用的單元或?qū)ο蠼M合而成。
基本介紹
????????OOP: Object Oriented Programming,面向?qū)ο蟮某绦蛟O(shè)計(jì)。所謂“對象”在顯式支持面向?qū)ο蟮恼Z言中,一般是指類在內(nèi)存中裝載的實(shí)例,具有相關(guān)的成員變量和成員函數(shù)(也稱為:方法)。面向?qū)ο蟮某绦蛟O(shè)計(jì)完全不同于傳統(tǒng)的面向過程程序設(shè)計(jì),它大大地降低了軟件開發(fā)的難度,使編程就像搭積木一樣簡單,是當(dāng)今電腦編程的一股勢不可擋的潮流。
????OOP 達(dá)到了軟件工程的三個(gè)主要目標(biāo):重用性、靈活性和擴(kuò)展性。為了實(shí)現(xiàn)整體運(yùn)算,每個(gè)對象都能夠接收信息、處理數(shù)據(jù)和向其它對象發(fā)送信息。OOP 主要有以下的概念和組件:
????????組件 - 數(shù)據(jù)和功能一起在運(yùn)行著的計(jì)算機(jī)程序中形成的單元,組件在 OOP 計(jì)算機(jī)程序中是模塊和結(jié)構(gòu)化的基礎(chǔ)。
????????抽象性 - 程序有能力忽略正在處理中信息的某些方面,即對信息主要方面關(guān)注的能力。
????????封裝 - 也叫做信息封裝:確保組件不會(huì)以不可預(yù)期的方式改變其它組件的內(nèi)部狀態(tài);只有在那些提供了內(nèi)部狀態(tài)改變方法的組件中,才可以訪問其內(nèi)部狀態(tài)。每類組件都提供了一個(gè)與其它組件聯(lián)系的接口,并規(guī)定了其它組件進(jìn)行調(diào)用的方法。
多態(tài)性?- 組件的引用和類集會(huì)涉及到其它許多不同類型的組件,而且引用組件所產(chǎn)生的結(jié)果依據(jù)實(shí)際調(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)了動(dòng)作的通用性。
????????由于抽象性、封裝性、重用性以及便于使用等方面的原因,以組件為基礎(chǔ)的編程在腳本語言中已經(jīng)變得特別流行。Python 和 Ruby 是最近才出現(xiàn)的語言,在開發(fā)時(shí)完全采用了 OOP 的思想,而流行的 Perl 腳本語言從版本5開始也慢慢地加入了新的面向?qū)ο?/a>的功能組件。用組件代替“現(xiàn)實(shí)”上的實(shí)體成為 JavaScript(ECMAScript) 得以流行的原因,有論證表明對組件進(jìn)行適當(dāng)?shù)慕M合就可以在英特網(wǎng)上代替 HTML 和 XML 的文檔對象模型(DOM)。
OOP思想
????????面向?qū)ο缶幊?/a>技術(shù)的關(guān)鍵性觀念是它將數(shù)據(jù)及對數(shù)據(jù)的操作行為放在一起,作為一個(gè)相互依存、不可分割的整體——對象。對于相同類型的對象進(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è)計(jì)(functional-programming)和邏輯式程序設(shè)計(jì)(logic-programming)所代表的接近于機(jī)器的實(shí)際計(jì)算模型所不同的是,OOP幾乎沒有引入精確的數(shù)學(xué)描敘,而是傾向于建立一個(gè)對象模型,它能夠近似的反映應(yīng)用領(lǐng)域內(nèi)的實(shí)體之間的關(guān)系,其本質(zhì)是更接近于一種人類認(rèn)知事物所采用的哲學(xué)觀的計(jì)算模型。由此,導(dǎo)致了一個(gè)自然的話題,那就是OOP到底是什么?[D&T 1988][B.S 1991] .。在OOP中,對象作為計(jì)算主體,擁有自己的名稱,狀態(tài)以及接受外界消息的接口。在對象模型中,產(chǎn)生新對象,舊對象銷毀,發(fā)送消息,響應(yīng)消息就構(gòu)成OOP計(jì)算模型的根本。
????????對象的產(chǎn)生有兩種基本方式。一種是以原型(prototype)對象為基礎(chǔ)產(chǎn)生新的對象。一種是以類(class)為基礎(chǔ)產(chǎn)生新對象。原型的概念已經(jīng)在認(rèn)知心理學(xué)中被用來解釋概念學(xué)習(xí)的遞增特性,原型模型本身就是企圖通過提供一個(gè)有代表性的對象為基礎(chǔ)來產(chǎn)生各種新的對象,并由此繼續(xù)產(chǎn)生更符合實(shí)際應(yīng)用的對象。而原型-委托也是OOP中的對象抽象,代碼共享機(jī)制中的一種。一個(gè)類提供了一個(gè)或者多個(gè)對象的通用性描述。從形式化的觀點(diǎn)看,類與類型有關(guān),因此一個(gè)類相當(dāng)于是從該類中產(chǎn)生的實(shí)例的集合。而這樣的觀點(diǎn)也會(huì)帶來一些矛盾,比較典型的就是在繼承體系下,子集(子類)對象和父集(父類)對象之間的行為相融性可能很難達(dá)到,這也就是OOP中常被引用的---子類型(subtype)不等于子類(subclass)[Budd 2002]。而在一種所有皆對象的世界觀背景下,在類模型基礎(chǔ)上還誕生出了一種擁有元類(metaclass)的新對象模型。即類本身也是一種其他類的對象。以上三種根本不同的觀點(diǎn)各自定義了三種基于類(class-based),基于原型(prototype-based)和基于元類(metaclass-based)的對象模型。而這三種對象模型也就導(dǎo)致了許多不同的程序設(shè)計(jì)語言(如果我們暫時(shí)把靜態(tài)與動(dòng)態(tài)的差別放在一邊)。是的,我們經(jīng)常接觸的C++,Java都是使用基于類的對象模型,但除此之外還有很多我們所沒有接觸的OOPL采用了完全不一樣的對象模型,他們是在用另外一種觀點(diǎn)詮釋OOP的內(nèi)涵。
????????什么是oop的基本思想呢?把組件的實(shí)現(xiàn)和接口分開,并且讓組件具有多態(tài)性。不過,兩者還是有根本的不同。oop強(qiáng)調(diào)在程序構(gòu)造中語言要素的語法。你必須得繼承,使用類,使用對象,對象傳遞消息。不關(guān)心你繼承或是不繼承,它的開端是分析產(chǎn)品的分類,有些什么種類,他們的行為如何。就是說,兩件東西相等意味著什么?怎樣正確地定義相等操作?不單單是相等操作那么簡單,你往深處分析就會(huì)發(fā)現(xiàn)“相等”這個(gè)一般觀念意味著兩個(gè)對象部分,或者至少基本部分是相等的,據(jù)此我們就可以有一個(gè)通用的相等操作。再說對象的種類。假設(shè)存在一個(gè)順序序列和一組對于順序序列的操作。那么這些操作的語義是什么?從復(fù)雜度權(quán)衡的角度看,我們應(yīng)該向用戶提供什么樣的順序序列?該種序列上存在那些操作?那種排序是我們需要的?只有對這些組件的概念型分類搞清楚了,我們才能提到實(shí)現(xiàn)的問題:使用模板、繼承還是宏?使用什么語言和技術(shù)?gp的基本觀點(diǎn)是把抽象的軟件組件和它們的行為用標(biāo)準(zhǔn)的分類學(xué)分類,出發(fā)點(diǎn)就是要建造真實(shí)的、高效的和不取決于語言的算法和數(shù)據(jù)結(jié)構(gòu)。當(dāng)然最終的載體還是語言,沒有語言沒法編程。stl使用c++,你也可以用ada來實(shí)現(xiàn),用其他的語言來實(shí)現(xiàn)也行,結(jié)果會(huì)有所不同,但基本的東西是一樣的。到處都要用到二分查找和排序,而這就是人們正在做的。對于容器的語義,不同的語言會(huì)帶來輕微的不同。但是基本的區(qū)別很清楚是gp所依存的語義,以及語義分解。例如,我們決定需要一個(gè)組件swap,然后指出這個(gè)組件在不同的語言中如果工作。顯然重點(diǎn)是語義以及語義分類。而oop所強(qiáng)調(diào)的(我認(rèn)為是過分強(qiáng)調(diào)的)是清楚的定義類之間的層次關(guān)系。oop告訴了你如何建立層次關(guān)系,卻沒有告訴你這些關(guān)系的實(shí)質(zhì)。
(這段不太好理解,有一些術(shù)語可能要過一段時(shí)間才會(huì)有合適的中文翻譯——譯者)
????????面向?qū)ο?/a>的編程方法OOP是九十年代才流行的一種軟件編程方法。它強(qiáng)調(diào)對象的“抽象”、“封裝”、“繼承”、“多態(tài)”。我們講程序設(shè)計(jì)是由“數(shù)據(jù)結(jié)構(gòu)”+“算法”組成的。從宏觀的角度講,OOP下的對象是以編程為中心的,是面向程序的對象。
特征
1.1面向?qū)ο蟪绦蛟O(shè)計(jì)的特征:
1) 封裝
2)?繼承
3)?多態(tài)
4)抽象
1.2類與數(shù)據(jù)封裝
1.2.1什么是類?
????????簡單的說,類就是一種用戶定義的數(shù)據(jù)類型,跟結(jié)構(gòu)類似;并且,類具有自己的成員變量和成員函數(shù)(方法),通過它們可以對類自身進(jìn)行操作。如:汽車可以看作是發(fā)動(dòng)機(jī)、車輪、座椅等諸如此類的集合。也可以從功能的角度來研究,譬如,能移動(dòng),加速,減速,剎車等。
例如:
class CMyClass1
{
protected:
CMyClass1();
public:
virtual ~ CMyClass1();
}
1.2.2?封裝(encapsulation)
定義:指能夠把一個(gè)實(shí)體的信息、功能、響應(yīng)都裝入一個(gè)單獨(dú)的對象中的特性。封裝的優(yōu)點(diǎn)如下:
1) 封裝允許類的客戶不必關(guān)心類的工作機(jī)理就可以使用它。就象駕駛員不必了解發(fā)動(dòng)機(jī)的工作原理就可以駕駛汽車一樣,類的客戶在使用一個(gè)類時(shí)也不必了解它是如何工作的,而只需了解它的功能即可。
2) 所有對數(shù)據(jù)的訪問和操作都必須通過特定的方法,否則便無法使用,從而達(dá)到數(shù)據(jù)隱藏的目的。
1.2.3?對象
????????對象就是類的實(shí)例。類與對象的關(guān)系就如類型和變量的關(guān)系,所有對類的操作都必須通過對象來實(shí)現(xiàn)。當(dāng)一個(gè)類定義了多個(gè)對象時(shí),每個(gè)對象擁有各自的成員數(shù)據(jù)。
1.2.4?類的三種成員類型
1) 私有成員(private):缺省情況下,一個(gè)類中的所有成員都是私有的。私有成員只能被類本身的成員函數(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)建對象時(shí)首先由系統(tǒng)自動(dòng)調(diào)用。它的作用是為新創(chuàng)建的對象分配空間,或?yàn)樵搶ο蟮?a target="_blank" rel="nofollow">成員變量賦值等;
b. 構(gòu)造函數(shù)名必須與其類名稱完全相同,并且不允許有返回值。
2)析構(gòu)函數(shù)
a. 析構(gòu)函數(shù)是構(gòu)造函數(shù)的逆操作;
b. 析構(gòu)函數(shù)在類名之前加~來命名,它不允許有返回值,也不允許帶參數(shù),并且一個(gè)類只能有一個(gè)析構(gòu)函數(shù)。
1.3繼承
1.3.1?傳統(tǒng)程序設(shè)計(jì)的缺點(diǎn):
增加功能對程序所作的修改工作量非常大。
1.3.2?繼承的優(yōu)點(diǎn):
????????繼承的方法允許在不改動(dòng)原程序的基礎(chǔ)上對其進(jìn)行擴(kuò)充,這樣使得原功能得以保存,而新功能也得以擴(kuò)展。這有利于減少重復(fù)編碼,提高軟件的開發(fā)效率。
1.3.3?基類與派生類
1)一個(gè)類可以繼承其它類的成員,被繼承的類叫基類或父類;繼承類叫派生類或子類
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í)擁有數(shù)據(jù)成員i和成員函數(shù)func1,類C引用基類的成員時(shí),系統(tǒng)無法分辨是調(diào)用哪一基類的成員而發(fā)生錯(cuò)誤;
3)解決多重繼承的不確定性:
使用域操作符指明要調(diào)用的基類,即可解決不確定性問題。
class C:public A,B
{
…
int j;
void Show()
{
j = A::i*B::i;
A::func1();
}
…
};
1.3.7?多層繼承
????????定義:所謂多層繼承指的是從一個(gè)類派生出另一個(gè)類,然后以派生類作為基類,派生出另一個(gè)類,直到最后生成的派生類滿足需要為止(見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) 在定義派生類對象時(shí),系統(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ù)個(gè)數(shù)或參數(shù)類型,則這些函數(shù)就是重載函數(shù)。
2)派生類繼承了基類的某一函數(shù),并且又自定義了一個(gè)同名函數(shù),有相同的返回值,不同的參數(shù)類型或參數(shù)個(gè)數(shù)。這種情況不屬于重載。因?yàn)樗鼈儗儆诓煌挠颉?/p>
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++中所定義的運(yùn)算符。然后像定義函數(shù)一樣定義重載操作符函數(shù)。
例子:
class person
{
…
int age;
void operator ++();
…
};
void person::operator++()
{
age++;
}
1.5虛擬函數(shù)與多態(tài)性
多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計(jì)的精髓之所在,也是C++中最難理解和掌握的部分。在C++中,多態(tài)性是建立在虛擬函數(shù)基礎(chǔ)上的,虛擬函數(shù)的使用使類的成員函數(shù)表現(xiàn)出多態(tài)性。
1.5.1虛擬函數(shù)
1)函數(shù)的定義:在定義類時(shí)在其成員函數(shù)前加上關(guān)鍵字virtual;
2)如果基類中成員函數(shù)定義為虛函數(shù),則派生類中與其定義完全相同的成員函數(shù),編譯器自動(dòng)將其視為虛函數(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) 反方向的賦值(將基類的對象或指針賦給派生類的對象或指針)是危險(xiǎn)的。
例:
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ù)在運(yùn)行時(shí)表現(xiàn)出多態(tài)功能;而重載函數(shù)不具有這一功能。
1.5.4純虛函數(shù)
定義:virtual type funcname(parameter)=0;
????????C++中有時(shí)設(shè)計(jì)基類就是為了被繼承,而基類中的虛擬函數(shù)不做任何工作,這種情況下可以將基類中的虛擬函數(shù)定義為純虛函數(shù)。包含純虛函數(shù)的類叫抽象類。抽象類不能定義對象,但可以定義指向它的指針。
歷史
????????面向?qū)ο蠹夹g(shù)最初是從面向?qū)ο蟮某绦蛟O(shè)計(jì)開始的,它的出現(xiàn)以60年代simula語言為標(biāo)志。80年代中后期,面向?qū)ο蟪绦蛟O(shè)計(jì)逐漸成熟,被計(jì)算機(jī)界理解和接受,人們又開始進(jìn)一步考慮面向?qū)ο蟮拈_發(fā)問題。這就是九十年代以Microsoft Visual系列OOP軟件的流行的背景。
????????傳統(tǒng)的結(jié)構(gòu)化分析與設(shè)計(jì)開發(fā)方法是一個(gè)線性過程,因此,傳統(tǒng)的結(jié)構(gòu)化分析與設(shè)計(jì)方法要求現(xiàn)實(shí)系統(tǒng)的業(yè)務(wù)管理規(guī)范,處理數(shù)據(jù)齊全,用戶能全面完整地其業(yè)務(wù)需求。
????????傳統(tǒng)的軟件結(jié)構(gòu)和設(shè)計(jì)方法難以適應(yīng)軟件生產(chǎn)自動(dòng)化的要求,因?yàn)樗赃^程為中心進(jìn)行功能組合,軟件的擴(kuò)充和復(fù)用能力很差。
????????對象是對現(xiàn)實(shí)世界實(shí)體的模擬,因面能更容易地理解需求,即使用戶和分析者之間具有不同的教育背景和工作特點(diǎn),也可很好地溝通。
區(qū)別面向?qū)ο?/a>的開發(fā)和傳統(tǒng)過程的開發(fā)的要素有:對象識別和抽象、封裝、多態(tài)性和繼承。
????????對象(Object)是一個(gè)現(xiàn)實(shí)實(shí)體的抽象,由現(xiàn)實(shí)實(shí)體的過程或信息牲來定義。一個(gè)對象可被認(rèn)為是一個(gè)把數(shù)據(jù)(屬性)和程序(方法)封裝在一起的實(shí)體,這個(gè)程序產(chǎn)生該對象的動(dòng)作或?qū)λ邮艿降耐饨缧盘柕姆磻?yīng)。這些對象操作有時(shí)稱為方法。對象是個(gè)動(dòng)態(tài)的概念,其中的屬性反映了對象當(dāng)前的狀態(tài)。
????????類(Class)用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個(gè)對象所共有的屬性和方法。對象是類的實(shí)例。
????????由上分析不難看出,盡管OOP技術(shù)更看中用戶的對象模型,但其目的都是以編程為目的的,而不是以用戶的信息為中心的,總想把用戶的信息納入到某個(gè)用戶不感興趣的“程序?qū)ο蟆敝小?/p>
優(yōu)缺點(diǎn)
·???????? OOP 的優(yōu)點(diǎn):使人們的編程與實(shí)際的世界更加接近,所有的對象被賦予屬性和方法,結(jié)果編程就更加富有人性化。
·???????? OOP 的也有缺點(diǎn),就 C++ 而言,由于面向更高的邏輯抽象層,使得 C++ 在實(shí)現(xiàn)的時(shí)候,不得不做出性能上面的犧牲,有時(shí)候甚至是致命的 ( 所有對象的屬性都經(jīng)過內(nèi)置多重指針的間接引用是其性能損失的主要原因之一;不過,筆者的局限性在于未使用過 VC++ 外的面向?qū)ο笳Z言,所以不是十分肯定,哈哈,有人笑出來了… )。
????????在計(jì)算機(jī)速度飛速發(fā)展的今天,你可能會(huì)說,一丁點(diǎn)的性能犧牲沒什么大不了。是的,從面向?qū)ο蟮慕嵌龋沟木幊痰慕Y(jié)構(gòu)更加清晰完整,數(shù)據(jù)更加獨(dú)立和易于管理,性能的犧牲可以帶來這么多的好處,沒有理由不做穩(wěn)賺的生意吧?
????????不過,在某些對速度要求極高特殊場合,例如你做的是電信的交換系統(tǒng),每秒鐘有超過百萬的人同時(shí)進(jìn)行電話交換,如果,每一個(gè)數(shù)據(jù)交換過程都是一個(gè)對象,那么總的性能損失將是天文數(shù)字!!
????????或者這個(gè)例子不夠貼身,再舉個(gè)例子吧。假如你受聘于一個(gè)游戲設(shè)計(jì)公司,老板希望做出來的游戲可以更多的兼顧到更多的電腦使用者,游戲每秒鐘的運(yùn)行的幀可以更多,子彈和爆炸物可以更多、更華麗。那么,你會(huì)發(fā)現(xiàn)使用 C++ 會(huì)使你的程序變得笨拙,無法滿足你的需求,除非你非得要你的游戲運(yùn)行于奔騰四的機(jī)器上 ( 如果不是,而你又堅(jiān)持用 C++ 的對象編程,那么請減少主角的槍的威力吧 )。
????????如果你是冥頑不靈的人,你說不相信 OOP 會(huì)有性能上的損失,那么,我記得曾看到在 CSDN 上關(guān)于 VB 和 VC 執(zhí)行效率的討論的文章,講述的就是使用了 MFC 以后,執(zhí)行效率甚至低于 VB 開發(fā)出來的東西。請各位驗(yàn)證一下:如果使用的是純粹的 C 語言語法的話,那么一定會(huì)比在 VB 編出來的東西要快很多 ( GetTickCount 函數(shù)可以查閱 MSDN ,如果想更加精確一些,可以使用 QueryPerformanceCounter 函數(shù) )。
未來
(撰文/Bjarne Stroustrup & Tim Lindholm 編譯/孟巖)
在未來三年,程序員編寫代碼的方式會(huì)發(fā)生哪些變化?
????????Stroustrup: 在C++中,假如沒有合適的庫在背后支撐,完成任何重要的工作都可能是很復(fù)雜的。而一旦有了合適的庫,任何東西都可以被我們操控于股掌之間。因此,構(gòu)造和使用程序庫的重要性與日俱增。這也暗示我們,泛型程序設(shè)計(jì)(generic programming)將會(huì)越來越多地被運(yùn)用。只有通過GP,我們才能確保庫的通用性和高效率。我還預(yù)期在分布式計(jì)算和“組件(components)”應(yīng)用領(lǐng)域會(huì)出現(xiàn)喜人的增長。就大部分程序員而言,通過使用方便適用的程序庫,這些開發(fā)工作會(huì)變得簡單明了。
????????現(xiàn)在有一個(gè)趨勢,編譯器廠商試圖把其特有的“對象模型”和圖形界面(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)該將對于平臺和廠家的依賴性限制起來。這個(gè)目標(biāo)的完成情況,可以反映軟件工具產(chǎn)業(yè)對于應(yīng)用程序開發(fā)行業(yè)的關(guān)注程度。我懷疑目前對于那些獨(dú)立的、跨平臺廠商來說,并不存在相應(yīng)的市場。如果能夠建立這樣的市場,也許能夠促進(jìn)廠商們?yōu)榭蛻糇龀觥罢嬲杏玫摹碑a(chǎn)品。
????????Lindholm: 對于編寫代碼的開發(fā)者來說,主要的驅(qū)動(dòng)力量仍將是兩個(gè):網(wǎng)絡(luò)和分布式——也就是設(shè)計(jì)和開發(fā)非單機(jī)軟件的需求。大部分的應(yīng)用程序?qū)⒉粫?huì)是孤零零地運(yùn)行在單一設(shè)備上,而是運(yùn)用了類似EJB和JSP之類技術(shù)的,平臺無關(guān)的分布式程序。程序員們將不得不面對分布式計(jì)算的重重險(xiǎn)阻。這將對許多程序員所依賴的設(shè)計(jì)模式、技術(shù)和直覺構(gòu)成嚴(yán)峻的挑戰(zhàn)。這是選擇編程語言之前必須認(rèn)識到的,盡管不同語言的設(shè)計(jì)特性可能促進(jìn)或者阻礙這一轉(zhuǎn)化。
????????在網(wǎng)絡(luò)應(yīng)用的增長中,一個(gè)很重要的部分是小型移動(dòng)設(shè)備和特殊Internet設(shè)備的爆炸性增長。這些設(shè)備各有各的操作系統(tǒng),或者只在某種特定的設(shè)備領(lǐng)域內(nèi)有共同的操作系統(tǒng)。我們現(xiàn)在還可以一一列舉出這些設(shè)備——家庭接入設(shè)備、蜂窩電話、電子報(bào)紙、PDA、自動(dòng)網(wǎng)絡(luò)設(shè)備等等。但是這些設(shè)備領(lǐng)域的數(shù)量和深入程度將會(huì)很快變得難以估量。我們都知道這個(gè)市場大得驚人,PC的興起與之相比不過小菜一碟。因此在這些設(shè)備的應(yīng)用程序市場上,競爭將會(huì)相當(dāng)殘酷。獲勝的重要手段之一,就是盡快進(jìn)入市場。開發(fā)人員需要優(yōu)秀的工具,迅速高效地撰寫和調(diào)試他們的軟件。平臺無關(guān)性也是制勝秘訣之一,它使得程序員能夠開發(fā)出支持多種設(shè)備平臺的軟件。
????????我預(yù)期的另一個(gè)變化是,我們對于代碼(Java)和數(shù)據(jù)(XML)協(xié)同型應(yīng)用程序的開發(fā)能力將會(huì)不斷提高。這種協(xié)同是開發(fā)強(qiáng)大應(yīng)用程序的核心目標(biāo)之一。我們從XML的迅速流行和ebXML規(guī)范的進(jìn)展中,已經(jīng)看到了這個(gè)趨勢。ebXML是一個(gè)針對電子商務(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)一個(gè)真正的面向組件(component-oriented)的語言?它的創(chuàng)造者會(huì)是誰呢?
????????Stroustrup: 我懷疑,這個(gè)領(lǐng)域中之所以缺乏成果,正是因?yàn)槿藗儭饕悄切┓浅绦騿T們——對“組件”這個(gè)意義含糊的字眼寄予了太多的期望。這些人士夢想,有朝一日,組件會(huì)以某種方式把程序員趕出歷史舞臺。以后那些稱職的“設(shè)計(jì)員”只需利用預(yù)先調(diào)整好的組件,把鼠標(biāo)拖一拖放一放,就把系統(tǒng)組合出來。對于軟件工具廠商來說,這種想法還有另一層意義,他們認(rèn)為,到時(shí)候只有他們才保留有必要的技術(shù),有能力編寫這樣的組件。
????????這種想法有一個(gè)最基本的謬誤:這種組件很難獲得廣泛歡迎。一個(gè)單獨(dú)的組件或框架(framework),如果能夠滿足一個(gè)應(yīng)用程序或者一個(gè)產(chǎn)業(yè)領(lǐng)域?qū)λ岢龅拇蟛糠忠蟮脑挘瑢τ谄渲圃煺邅碚f就是劃算的產(chǎn)品,而且技術(shù)上也不是很困難。可是該產(chǎn)業(yè)內(nèi)的幾個(gè)競爭者很快就會(huì)發(fā)現(xiàn),如果所有人都采用這些組件,那么彼此之間的產(chǎn)品就會(huì)變得天下大同,沒什么區(qū)別,他們將淪為簡單的辦事員,主要利潤都將鉆進(jìn)那些組件/框架供應(yīng)商的腰包里!
小“組件”很有用,不過產(chǎn)生不了預(yù)期的杠桿效應(yīng)。中型的、更通用的組件非常有用,但是構(gòu)造時(shí)需要非同尋常的彈性。
????????在C++中,我們綜合運(yùn)用不同共享形式的類體系(class hierarchies),以及使用templates精心打造的接口,在這方面取得了一定的進(jìn)展。我期待在這個(gè)領(lǐng)域取得一些有趣和有用的成果,不過我認(rèn)為這種成果很可能是一種新的C++程序設(shè)計(jì)風(fēng)格,而不是一種新的語言。
????????Lindholm: 編寫面向組件的應(yīng)用程序,好像更多的是個(gè)投資、設(shè)計(jì)和程序員管理方面的問題,而不是一個(gè)編程語言問題。當(dāng)然某些語言在這方面具有先天優(yōu)勢,不過如果說有什么魔術(shù)般的新語言能夠大大簡化組件的編寫難度,那純粹是一種誤導(dǎo)。
微軟已經(jīng)將全部賭注押在C#上,其他語言何去何從?
????????Stroustrup: C++在下一個(gè)十年里仍然將是一種主流語言。面對新的挑戰(zhàn),它會(huì)奮起應(yīng)對。一個(gè)創(chuàng)造了那么多出色系統(tǒng)的語言,絕不會(huì)“坐視落花流水春去也”。
????????我希望微軟認(rèn)識到,它在C++(我指的是ISO標(biāo)準(zhǔn)C++)上有著巨大的利益,C++是它與IT世界內(nèi)其他人之間的一座橋梁,是構(gòu)造大型系統(tǒng)和嵌入式系統(tǒng)的有效工具,也是滿足高性能需求的利器。其他語言,似乎更注重那些四平八穩(wěn)的商用程序。
競爭
C#會(huì)不會(huì)獲得廣泛的接受,并且擠掉其他的語言?
????????Lindholm: 通常,一種語言既不會(huì)從別的語言那里獲利,也不會(huì)被擠掉。那些堅(jiān)定的Fortran程序員不還用著Fortran嗎?對于個(gè)人來說,語言的選擇當(dāng)然因時(shí)而異,但就整體而言,語言的種類只會(huì)遞增,也就是說,它們之間的關(guān)系是“有你有我”而不是“有你沒我”。
????????對于一個(gè)新語言的接受程度,往往取決于其能力所及。Java技術(shù)被迅速接受,原因是多方面的,Internet和World Wide Web接口,在其他技術(shù)面前的挫折感,對于Java技術(shù)發(fā)展方向的全面影響能力,都是原因。另一個(gè)重要的原因是Java獨(dú)立于廠商,這意味著在兼容產(chǎn)品面前可以從容選擇。
????????C#是否會(huì)獲得廣泛接受?視情況而定。總的來說,那些對于平臺無關(guān)性和廠商無關(guān)性漠不關(guān)心的程序員,可能會(huì)喜歡C#。那些跟微軟平臺捆在一起人當(dāng)然可能想要尋找VB 和VC的一個(gè)出色的替代品。但是對于程序跨平臺執(zhí)行能力特別關(guān)注的程序員,將會(huì)堅(jiān)守Java之類的語言。這種能力對于多重訪問設(shè)備(multiple access devices)和分布式計(jì)算模型至關(guān)重要,而Java語言提供了一個(gè)標(biāo)準(zhǔn)的、獨(dú)立于廠商運(yùn)行時(shí)環(huán)境。
????????Stroustrup:C#的流行程度幾乎完全取決于微軟投入的資金多少。看上去C#的興起肯定會(huì)犧牲掉其他一些語言的利益,但是事實(shí)上未必如此。Java的蓬勃發(fā)展并沒有給C++帶來衰敗。C++的應(yīng)用仍然在穩(wěn)定增長(當(dāng)然,已經(jīng)不是爆炸性的增長了)。也許其他的語言也還能獲得自己的一席之地。
不過,我實(shí)在看不出有什么必要再發(fā)明一種新的專有語言。特別是微軟,既生VB,何需C#?
優(yōu)劣勢
????????Stroustrup: C++的優(yōu)點(diǎn)自始至終都是這么幾條:靈活、高效,而且并非專有語言。現(xiàn)在ISO C++標(biāo)準(zhǔn)的出現(xiàn),鞏固了最后一點(diǎn)。
????????我認(rèn)為C++的高效是它最基本的優(yōu)點(diǎn)。這種高效來自于其特有的數(shù)據(jù)和計(jì)算模型,較之Java和C#,這種模型更加貼近機(jī)器。不過,哪些程序才真正地渴望這么高的效率?這是個(gè)問題。我認(rèn)為這類程序非常多。人們對于計(jì)算機(jī)的期望,永遠(yuǎn)都超越硬件科技的發(fā)展速度。很顯然,Java和C#的設(shè)計(jì)者的想法不同,他們認(rèn)為,在很多地方效率問題無關(guān)緊要。
????????C++主要的缺點(diǎn),歸罪于糟糕的教育(是那些始終認(rèn)為C++是個(gè)純粹面向?qū)ο笳Z言的人,和那些把C++當(dāng)成C語言變體的人導(dǎo)致了這種情況),歸罪于不同平臺上的不一致性,歸罪于不完整、不標(biāo)準(zhǔn)的編譯器實(shí)現(xiàn),歸罪于平臺無關(guān)的系統(tǒng)級程序庫的缺少。
這些問題歸于一點(diǎn),就是缺乏一個(gè)卓越的廠商,能夠滿足整個(gè)C++社區(qū)的需求,勇于投入大量的資金開發(fā)必要的程序庫。
????????Lindholm: Java技術(shù)的成功,是因?yàn)樗诤线m的時(shí)間,出現(xiàn)在合適的地點(diǎn),而且合理地選擇了語言和計(jì)算平臺的支持目標(biāo)。Java并不是在所有場合都優(yōu)于其他OOP語言,但是對于出現(xiàn)的新問題能夠解決得很出色。它面向Internet計(jì)算環(huán)境,避免了C++中晦澀的結(jié)構(gòu),成功翻越了繼承機(jī)制的惱人問題。垃圾收集機(jī)制顯著地提高了生產(chǎn)率,降低了復(fù)雜度。在網(wǎng)絡(luò)背景下使用虛擬機(jī),以及有關(guān)安全性和動(dòng)態(tài)加載的一系列設(shè)計(jì)選擇,迎合了正在出現(xiàn)的需求和愿望。這些特性使Java不僅成為現(xiàn)有程序員的新武器,而且也為新的程序員創(chuàng)造了繁榮的市場空間。
????????此外,Java擁有一個(gè)標(biāo)準(zhǔn)化的、二進(jìn)制形式的類庫,提供了必要的(當(dāng)然并非充分的)平臺與廠商無關(guān)性。平臺與廠商無關(guān)性要求一項(xiàng)技術(shù)必須有清晰的規(guī)范,摒棄那些阻礙二進(jìn)制標(biāo)準(zhǔn)實(shí)施的特性。C++雖然有一個(gè)ISO標(biāo)準(zhǔn),但其實(shí)甚至對于相同系統(tǒng)與相同指令體系的各個(gè)平臺,也提不出一個(gè)實(shí)用的、各版本兼容的二進(jìn)制標(biāo)準(zhǔn)。
????????歷史上很多使用虛擬機(jī)的語言飽受責(zé)難,是因?yàn)槠洳粔虺錾男阅軉栴},而這要?dú)w過于緩慢的解釋器和糟糕的垃圾收集器。Java的早期實(shí)現(xiàn)也因?yàn)橥瑯拥膯栴}受到嚴(yán)厲的批評。但是自那時(shí)起,業(yè)界向新的虛擬機(jī)實(shí)現(xiàn)技術(shù)投入了大量資金,取得了顯著的效果,如今在大部分場合,Java的性能跟常規(guī)的靜態(tài)編譯語言相比毫不遜色。這使得程序員在獲得平臺和廠商無關(guān)性的同時(shí),也不必付出性能上的代價(jià)。
????????C++并沒有強(qiáng)制使用面向?qū)ο蠓椒?/a>,因此為了編寫出色的面向?qū)ο蟠a,就要求程序員們有相當(dāng)強(qiáng)的紀(jì)律性。很多公司就是因?yàn)檫@個(gè)原因放棄了C++。作為語言,Java的一個(gè)突出的優(yōu)點(diǎn)就是強(qiáng)制面向?qū)ο?/a>方法,不允許非面向?qū)ο蟮慕Y(jié)構(gòu)。
C#介于C++和Java之間,腳踏兩只船,因此既不夠安全,又失之復(fù)雜。
????????對于公司來說,采用新的語言要付出巨大代價(jià)。雇不到好的程序員(沒人熟悉這種新語言),培訓(xùn)費(fèi)用高得驚人,學(xué)習(xí)過程中生產(chǎn)率和產(chǎn)品質(zhì)量下降,多年的經(jīng)驗(yàn)隨風(fēng)消逝,等等。一種語言如何克服這些障礙?
????????Lindholm: 說得很對,采用新東西確實(shí)常常開銷巨大。不過問題是:這個(gè)新東西是否能夠節(jié)省更多的開支,或者提供巨大的改進(jìn),獲取合理的回報(bào)?很多公司發(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)時(shí)很多系統(tǒng)的缺陷所做出的反應(yīng)。Java技術(shù)通過下面的手段減輕了開發(fā)者的痛楚:1) 顧及了網(wǎng)絡(luò)計(jì)算方面的需求,是應(yīng)運(yùn)而生。2) 在技術(shù)能力的抉擇上,保持良好的品位,顧及了大眾的心理。3) 采用適度強(qiáng)制性策略推行設(shè)計(jì)決定。此外,Java技術(shù)已經(jīng)成為大學(xué)教學(xué)中的主流,這同樣保證了Java開發(fā)者隊(duì)伍的不斷壯大。
????????但是最重要的一點(diǎn)是,再?zèng)]有另一種程序設(shè)計(jì)技術(shù),能夠像Java那樣允許程序員開發(fā)基于Internet的不同平臺之上的應(yīng)用程序。Java平臺在這方面的杰出表現(xiàn),已經(jīng)被大量的實(shí)例證明。Java已經(jīng)成為Internet上的缺省應(yīng)用程序平臺,Java APIs也成為Internet應(yīng)用程序開發(fā)的天然平臺。
????????Stroustrup: 微軟和Sun把大筆的金錢扔在Java、VB和C#中,并不是因?yàn)樗夹陌l(fā)現(xiàn),也不是因?yàn)樗麄冋娴南嘈胚@些語言能夠帶給程序員更美好的生活,而是利益使然。
????????有一個(gè)說法,認(rèn)為軟件工具廠商如果能夠把應(yīng)用程序開發(fā)者的專業(yè)技術(shù)任務(wù)負(fù)擔(dān)起來,將獲取巨大的經(jīng)濟(jì)利益。我對其背后的經(jīng)濟(jì)分析頗為懷疑,我認(rèn)為這很難成為現(xiàn)實(shí),特別是當(dāng)應(yīng)用程序開發(fā)者使用開放的、標(biāo)準(zhǔn)化的工具時(shí),他們可以有多種選擇,從而使上面的想法更加不可能。
????????多年以前,C++就已經(jīng)具有泛型能力(也就是templates和STL),有運(yùn)算符重載,有枚舉類型?我們會(huì)不會(huì)在Java的未來版本中看到這些特性?Java是不是應(yīng)該納入這些特性呢?
????????Strousturp:從1988-89年起,C++就已經(jīng)有了templates。但是我們花了不少時(shí)間來了解如何最好地運(yùn)用這個(gè)工具,早期各廠家對于template的支持在品質(zhì)上也有很大的差異。有些編譯器廠商動(dòng)作遲緩,至少有一個(gè)主要的編譯器廠商(好像是指微軟,微軟在Visual C++4.0才開始支持template,在此之前一直聲稱template是過于復(fù)雜而又沒什么用的技術(shù),時(shí)至今日,Visual C++對于template的支持在主流編譯器中都屬于最差的一檔——譯者注)暗中鼓勵(lì)聲名狼藉的反template宣傳,直到他們自己終于學(xué)會(huì)了這項(xiàng)技術(shù)為止。直到今天,對于template的支持在品質(zhì)上仍然有待改進(jìn)。
????????你上面提到的那些特性,我認(rèn)為Java(還有C#)應(yīng)該,也肯定會(huì)逐漸引入。那些對于程序員來說最有用的語言特性和概念,將會(huì)逐漸集中,成為各家主流語言的必然之選。也就是說,我認(rèn)為類似析構(gòu)函數(shù)和模板特殊化之類的機(jī)制,遠(yuǎn)遠(yuǎn)比枚舉等機(jī)制重要得多。
????????Lindholm:Java技術(shù)成功的原因之一,就是很清楚哪些不該做。我們得多問幾個(gè)為什么:這項(xiàng)特性是不是必不可少?增加它會(huì)帶來哪些開銷?運(yùn)算符重載是C++中一項(xiàng)極其強(qiáng)大的特性,但是它也大大增加了C++語言的復(fù)雜度,很多人都難以招架。Java在各種可能的權(quán)衡之中,做出了明智的抉擇,找到了能力與需求之間的完美平衡點(diǎn)。
????????當(dāng)然,Java也會(huì)發(fā)展,而且最重要的是,現(xiàn)在是開發(fā)者們在推動(dòng)發(fā)展。Java增加泛型能力這件事,很好地展示了Java是如何通過整個(gè)開發(fā)者社群的參與,在權(quán)衡中決定正確的平衡點(diǎn)。關(guān)于增加泛型類型(generic types)的“Java規(guī)格申請”(Java Specification Request, JSR)已經(jīng)進(jìn)入JCP(Java Community Process)程序,而且已經(jīng)開發(fā)了很長一段時(shí)間。現(xiàn)在,在JCP中,有超過80個(gè)JSRs正在討論中,這充分體現(xiàn)了整個(gè)體系對開發(fā)者的積極反饋和高度合作,這正是驅(qū)動(dòng)Java平臺不斷進(jìn)化的動(dòng)力。