OOP 面向?qū)ο缶幊?/h1>

????????面向?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)力。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容