国产18禁黄网站免费观看,99爱在线精品免费观看,粉嫩metart人体欣赏,99久久99精品久久久久久,6080亚洲人久久精品

計(jì)算機(jī)二級C++輔導(dǎo):面向?qū)ο笳Z言概論(三)

時(shí)間:2009-04-10 15:20:00   來源:無憂考網(wǎng)     [字體: ]
傳統(tǒng)的基于類的面向?qū)ο笳Z言的一個(gè)主要特點(diǎn)就是inheritance, subclassing和subtyping之間的密不可分的聯(lián)系。很多的面向?qū)ο笳Z言的語法,概念,就是從這三者而來的。比如說,通過subclassing, 你可以繼承父類的一些方法,而同時(shí)你又可以在子類中改寫父類的方法。這個(gè)改寫過的方法,通過subtyping, subsumption, 又可以從一個(gè)類型是父類的對象去調(diào)用。
  但是,inheritance, subclassing, subtyping這三者并不是永遠(yuǎn)和睦相處的。在一些場合,這三者之間的糾纏不清會妨礙到通過繼承或泛型得到的代碼重用。因此,人們開始注意到把這三者分離開來的可能性。區(qū)分subclassing和subtyping已經(jīng)很常見了。而其它的一些方法還處于研究的階段。這一章我們將介紹這樣一些方法。
  一,對象類型
  在早期的面向?qū)ο笳Z言中(如Simula), 類型的定義是和方法的實(shí)現(xiàn)是混合在一起的。這種方式違反了我們今天已經(jīng)被廣泛認(rèn)識到的把實(shí)現(xiàn)和規(guī)范(Specification) 分離的原則。這種分離得原則在開發(fā)是團(tuán)隊(duì)進(jìn)行的時(shí)候尤其顯得重要。
  更近期一些的語言,通過引入不依賴于實(shí)現(xiàn)的對象類型來區(qū)分實(shí)現(xiàn)和規(guī)范。Modula-3以及其它如Java等的支持class和interface的語言都是采用的這種技術(shù)。
  在本書中,我們開始引入InstanceTypeOf(cell)時(shí),它代表的概念相當(dāng)有限?瓷先,它似乎只表示用new cell生成的對象的類型,于是,我們并不能用它來表示從其它類new出來的對象。但后來,當(dāng)我們引入了subclassing, method overriding, subsumption和dynamic dispatch之后,事情變得不那么簡單了。我們的InstanceTypeOf(cell)已經(jīng)可以用來表示從cell的子類new出來的對象,這些對象可以包括不是cell類定義的屬性和方法。
  如此看來,讓InstanceTypeOf(cell)依賴于一個(gè)具體的類似乎是不合理的。實(shí)際上,一個(gè)InstanceTypeOf(cell)類型的對象不一定會跟class cell扯上任何關(guān)系。
  它和cell類的共同之處只是它具有了所有cell類定義的方法的簽名(signature).
  基于這種考慮,我們可以引入對象類型的語法:
  針對cell類和reCell類的定義:
  class cell is
  var contents: Integer :=0;
  method get(): Integer is
  return self.contents;
  end;
  method set(n:Integer) is
  self.contents := n;
  end;
  end;
  subclass reCell of cell is
  var backup: Integer := 0;
  override set(n: Integer) is
  self.backup := self.contents;
  super.set(n);
  end;
  method restore() is
  self.contents := self.backup;
  end;
  end;
  我們可以給出這樣的對象類型定義:
  ObjectType Cell is
  var contents: Integer;
  method get(): Integer;
  method set(n:Integer);
  end;
  ObjectType ReCell is
  var contents: Integer;
  var backup: Integer;
  method get(): Integer
  method set(n: Integer);
  method restore();
  end;
  這兩個(gè)類型的定義包括了所有cell類和reCell類定義的屬性和方法的類型,但卻并不包括實(shí)現(xiàn)。這樣,它們就可以被當(dāng)作與實(shí)現(xiàn)細(xì)節(jié)無關(guān)的的接口以實(shí)現(xiàn)規(guī)范和實(shí)現(xiàn)的分離。兩個(gè)完全無關(guān)的類c和c’, 可以具有相同的類型Cell, 而Cell類型的使用者不必關(guān)心它使用的是c類還是c’類。
  注意,我們還可以加入額外的類似繼承的語法來避免在ReCell里重寫Cell里的方法簽名。但那只是小節(jié)罷了。
  二,分離Subclassing和Subtyping.
  在我們上一章的討論中,subtype的關(guān)系是建立在subclass關(guān)系的基礎(chǔ)上的。但如果我們想要讓type獨(dú)立于class, 那么我們也需要定義獨(dú)立于subclass的subtype.
  在定義subtype時(shí),我們又面臨著幾種選擇:subtype是由類型的組成結(jié)構(gòu)決定的呢?還是由名字決定呢?
  由類型的組成結(jié)構(gòu)決定的subtype是這樣的:如果類型一具有了類型二的所有需要具備的屬性和方法,我們就說類型一是類型二的subtype.
  由類型名字決定的subtype是這樣的:只有當(dāng)類型一具有了類型二的所有需要具備的屬性和方法, 并且類型一被明確聲明為類型二的subtype時(shí),我們才認(rèn)可這種關(guān)系。
  而如果我們的選擇是一,那么那些屬性和方法是subtype所必需具備的呢?哪些是可有可無的呢?
  由組成結(jié)構(gòu)決定的subtype能夠在分布式環(huán)境和object persistence系統(tǒng)下進(jìn)行類型匹配(譯者注:對這點(diǎn),我也不甚明了。看來,紙?jiān)斓眠是不夠)。缺點(diǎn)是,如果兩個(gè)類型碰巧具有了相同的結(jié)構(gòu),但實(shí)際上卻風(fēng)馬牛不相及,那就會造成錯(cuò)誤。不過,這種錯(cuò)誤是可以用一些技術(shù)來避免的。
  相比之下,基于名字的subtype不容易精確定義,而且也不支持基于結(jié)構(gòu)的subtype.
  (譯者按,這里,我無論如何和作者找不到同感;诮Y(jié)構(gòu)的subtype的缺點(diǎn)是一目了然,不過完美的避免的方法我卻看不出來。而基于名字的subtype為什么就不能精確定義呢?C++/Java/C#, 所有流行的OO語言都只支持基于名字的subtype, 也沒有發(fā)現(xiàn)有什么不夠靈活的地方。需要在不同名字但類似結(jié)構(gòu)的類型之間架橋的話,adapter完全可以勝任嘛!)
  目前,我們可以先定義一個(gè)簡單的基于結(jié)構(gòu)的subtype關(guān)系:
  對兩個(gè)類型O和O’,
  O’ <: O 當(dāng) O’ 具有所有O類型的成員。O’可以有多于O的成員。
  例如:ReCell <: Cell.
  為了簡明,這個(gè)定義沒有考慮到方法的特化。
  另外,當(dāng)類型定義有遞歸存在的時(shí)候(類似于鏈表的定義),對subtype的定義需要額外地加小心。我們會在第九章及之后章節(jié)講到遞歸的時(shí)候再詳細(xì)說明。(譯者按:第九章。筐埩宋野!想累死我?)
  因?yàn)槲覀儾魂P(guān)心成員的順序,這種subtype的定義自動地就支持多重的subtype.
  比如說:
  ObjectType ReInteger is
  var contents: Integer;
  var backup: Integer;
  method restore();
  end;
  那么,我們就有如下的subtype的關(guān)系:
  ReCell <: Cell
  ReCell <: ReInteger
  (譯者按,作者的例子中沒有考慮到象interface不能包含數(shù)據(jù)域這樣的細(xì)節(jié)。實(shí)際上,如果我們支持對數(shù)據(jù)域的override, 而不支持shadowing -- 作者的基于結(jié)構(gòu)的subtype語義確實(shí)隱含著這樣的邏輯― 那么,interface里包含不包含數(shù)據(jù)域就無關(guān)緊要了,因?yàn)榱钊祟^疼的名字沖突問題已經(jīng)不存在了)
  從這個(gè)定義,我們可以得出:
  如果c’是c的子類, 那么ObjectTypeOf(c’) <: ObjectTypeOf(c)
  注意,這個(gè)定義的逆命題并不成立,也就是說:
  即使c’和c之間沒有subclass的關(guān)系,只要它們所定義的成員符合了我們subtype的定義,ObjectTypeOf(c’) <: ObjectTypeOf(c)仍然成立。
  回過頭再看看我們在前一章的subclass-is-subtyping:
  InstanceTypeOf(c’) <: InstanceTypeOf(c) 當(dāng)且僅當(dāng) c’是c的子類在那個(gè)定義中,只有當(dāng)c’是c的子類時(shí),ObjectTypeOf(c’) <: ObjectTypeOf(c)才能成立。
  相比之下,我們已經(jīng)部分地把subclassing和subtyping分離開了。Subclassing仍然是subtyping, 但subtyping不再一定要求是subclassing了。
  我們把這種性質(zhì)叫做“subclassing-implies-subtyping”而不是“subclass-is-subtyping”了。
  三,泛型 (Type Parameters)
  一般意義上來說,泛型是一種把相同的代碼重用在不同的類型上的技術(shù)。它作為一個(gè)相對獨(dú)立于其它面向?qū)ο筇匦缘募夹g(shù),在面向?qū)ο笳Z言里已經(jīng)變得越來越普遍了。我們這里之所以討論泛型,一是因?yàn)榉盒瓦@種技術(shù)本身就很讓人感興趣,另外,也是因?yàn)榉盒褪且粋(gè)被用來對付二元方法問題(binary method problem) 的主要工具。
  和subtyping共同使用,泛型可以用來解決一些在方法特化等場合由反協(xié)變帶來的類型系統(tǒng)的困難。考慮這樣一個(gè)例子:
  我們有Person和Vegitarian兩種類型,同時(shí),我們有Vegitable和Food兩種類型。而且,Vegitable <: Food.
  ObjectType Person is
  …
  method eat(food: Food);
  end;
  ObjectType Vegetarian is
  …
  method eat(food: Vegitable);
  end;
  這里,從常識,我們知道一個(gè)Vegitarian是一個(gè)人。所以,我們希望可以有Vegetarian <: Person.
  不幸的是,因?yàn)閰?shù)是反協(xié)變的,如果我們錯(cuò)誤地認(rèn)為Vegetarian <: Person, 根據(jù)subtype的subsumption原則,一個(gè)Vegetarian的對象就可以被當(dāng)作Person來用。于是一個(gè)Vegetarian就可以錯(cuò)誤地吃起肉來。
  使用泛型技術(shù),我們引入Type Operator (也就是,從一個(gè)類型導(dǎo)出另一個(gè)類型,概念上類似于對類型的函數(shù))。
  ObjectOperator PersonEating[F<:Food] is
  …
  method eat(food: F);
  end;
  ObjectOperator VegetarianEating[F<: Vegetable] is
  …
  method eat(food: F);
  end;
  這里使用的技術(shù)被稱作Bounded Type Parameterization. (Trelli/Owl, Sather, Eiffel, PolyTOIL, Raptide以及Generic Java都支持Bounded Type Parameterization. 其它的語言,如C++, 只支持簡單的沒有類型約束的泛型)
  F是一個(gè)類型參數(shù),它可以被實(shí)例化成一個(gè)具體的類型。 類似于變量的類型定義,一個(gè)bound如F<:Vegitable限制了F只能被Vegitable及其子類型所實(shí)例化。所以,VegitarianEating[Vegitable], VegitarianEating[Carrot]都是合法的類型。而VegitarianEating[Beef]就不是一個(gè)合法的類型。類型VegitarianEating[Vegitable]是VegitarianEating的一個(gè)實(shí)例,同時(shí)它等價(jià)于類型Vegitarian. (我們用的是基于結(jié)構(gòu)的subtype)
  于是,我們有:
  對任意F<:Vegitable, VegitarianEating[F] <: PersonEating[F]
  對于原來的Vegitarian類型,我們有:
  Vegetarian = VegetarianEating[Vegetable] <: PersonEating[Vegitable]
  這種關(guān)系,正確地表達(dá)了“一個(gè)素食者是一個(gè)吃蔬菜的人”的概念。
  除了Bounded Type Parameterization之外,還有一種類似的方法也可以解決這個(gè)素食者的問題。這種方法被叫做:Bounded Abstract Type請看這個(gè)定義:
  ObjectType Person is
  Type F<: Food;
  …
  var lunch: F;
  method eat(food: F);
  end;
  ObjectType Vegetarian is
  Type F<: Vegitable;
  …
  var lunch: F;
  method eat(food: F);
  end;
  這里,F(xiàn)<:Food的意思是,給定一個(gè)Person, 我們知道他能吃某種Food, 但我們不知道具體是哪一種。這個(gè)lunch的屬性提供這個(gè)Person所吃的Food.
  在創(chuàng)建Person對象時(shí),我們可以先選定一個(gè)Food的subtype, 比如說,F(xiàn)=Dessert. 然后,用一個(gè)Dessert類型的變量賦給屬性lunch. 最后再實(shí)現(xiàn)一個(gè)eat(food:Dessert)的方法。
  這樣,Vegetarian <: Person是安全的了。當(dāng)你把一個(gè)Vegetarian當(dāng)作一個(gè)Person處理時(shí),這個(gè)Vegitarian可以安全地吃他自帶的午餐,即使你不知道他吃的是肉還是菜。
  這種方法的局限在于,Person, Vegitarian只能吃他們自帶的午餐。你不能讓他們吃買來的午餐。