讀《C++沉思錄》有感

關(guān)于類的設(shè)計:代理類

《C++沉思錄》的原話是這樣的

我們怎樣才能設(shè)計一個C++容器,使它有能力包含類型不同而彼此相關(guān)的對象呢?

我們從為什么需要這么一個容器開始討論翠胰。

假設(shè)我們要設(shè)計一個停車場候引,這個停車場就是一個容器。那么停車場需要停各種不同的車輛佑菩,不同的車輛就是不同的類,但他們都是有關(guān)系的(都是交通工具)裁赠。我們知道殿漠,C++標(biāo)準(zhǔn)的容器中儲存的都是相同類型的類,例如數(shù)組佩捞,vector......那么原有的容器就無法滿足我們停車場的需求了绞幌。 所以我們就需要一個能包含類型不同而彼此相關(guān)的對象(車)

下面我們來模擬整個流程

  • 在有停車場之前,要先有車一忱。因此莲蜘,首先需要一個抽象基類,命名為Vehicle帘营。它有一系列的派生實類:Automobile,Truck......
class Vehicle{ 
public:
           virtual double weight() const = 0;
           virtual void start() = 0;
           // ...
};
class Automobile: public Vehicle {/*...*/};
class Truck: public Vehicle {/*...*/};
......

  • 現(xiàn)在我們來模擬停車場(容器)票渠。這個停車場到底需要什么功能呢?
    (1)停車場實際上是不需要知道到底是什么車停進(jìn)來的芬迄,只需要知道它是車问顷。
    (2)有車進(jìn)來的時候,我們能跟蹤它禀梳,給一個車位(內(nèi)存)給它杜窄。
    (3)車換位置停的時候,我們要知道它換到哪了算途。
    (4)當(dāng)車離開的時候塞耕,我們要把車位(內(nèi)存)釋放。
    我們通常的做法是用一個指針數(shù)組
Vehicle* parking_lot[1000];
Automobile x = /*.....*/;
parking_lot[num_vehicles++] = &x;
//num_vehicles means numbers of vehicles

這么做有一個弊端嘴瓤,這個指針是直接指向車本身的扫外。打個比方,假如車開出了停車場廓脆,理論上來說畏浆,這個指針還會跟著車走,但我的指針是屬于停車場的狞贱,出不去刻获,那么車開出去的時候這個指針指向哪里就out of control

既然這樣,那我們來做第一個變通蝎毡。我們不讓指針指向車本身厚柳,我們指向它的一個副本。

Automobile x = /*.....*/;
parking_lot[num_vehicles++] = new Automobile(x);

我簡單解釋一下第二行等號右邊代碼的意思:new操作符分配了一塊內(nèi)存(車位)沐兵,返回指向這塊內(nèi)存的指針别垮,大小為Automobile這么大;Automobile(x)是一個復(fù)制構(gòu)造函數(shù)扎谎,返回值是一個和x一樣的類碳想。
這個做法有兩個弊端:1. 增加顯示動態(tài)內(nèi)存管理的負(fù)擔(dān)。2. 我需要確切知道它是什么類型毁靶。 但實際上胧奔,停車場并不需要它到底是哪款車型,只要知道有車進(jìn)來就行了预吆。


如果代碼是這樣的龙填,就很簡潔了

Automobile x = /*.....*/;
parking_lot[num_vehicles++] = x;

不需要顯示的處理內(nèi)存,不需要判斷車的類型拐叉。


如何做到既能避免顯示的處理內(nèi)存分配岩遗,又能保持類在運(yùn)行時綁定的屬性呢?
解決這個問題的關(guān)鍵是要用類來表示概念凤瘦,這在C++中是很常見的宿礁。我總是把這一點當(dāng)作最基本的C++設(shè)計原則。在復(fù)制對象的過程中運(yùn)用這個設(shè)計原則蔬芥,就是定義一個行為和Vehicle對象相似梆靖,而又潛在的表示了所有繼承自Vehicle類的對象的東西,我們把這種類的對象叫做代理(surrogate)

講到這里坝茎,相信大家都應(yīng)該明白涤姊,實際上暇番,停車場需要操作的實際上是車位嗤放,并不是車輛。車位壁酬,是一個跟車輛綁定的東西次酌。在這個例子中,我們可以把車位理解成車輛類的代理舆乔。


無論是第一種變通辦法還是定義代理岳服,我們都需要一個操作,就是復(fù)制copy(),因此希俩,我們需要更新一下車輛類的定義

class Vehicle{ 
public:
           virtual double weight() const = 0;
           virtual void start() = 0;
           virtual Vehicle* copy() const = 0;
           virtual ~Vehicle() { }
           // ...
};

Vehicle* Automobile::copy() const{
          return new Automobile(*this);
}
......

有了虛函數(shù)copy來完成復(fù)制工作吊宋,那么代理類(車位)就比較好寫了:

class VehicleSurrogate{
public:
          VehicleSurrogate();
          VehicleSurrogate(const Vehicle&);
          ~VehicleSurrogate();
          VehicleSurrogate(const  VehicleSurrogate&);
          VehicleSurrogate& operate=(const VehicleSurrogate&);
          //來自類Vehicle的操作
          double weight() const;
          void start();
          //...
private:
          Vehicle* vp;
}

值得注意的是,在代理類(車位)中颜武,我們重載了賦值符‘=’璃搜。目的是為了后續(xù)代碼的簡潔拖吼。(上述代碼只給出了定義,具體實現(xiàn)比較簡單这吻,需要的私聊)


完成了上述的工作吊档,我們的停車場基本就很容易定義了。

VehicleSurrogate parking_lot[1000];
Automobile x;
parking_lot[num_vehicles++] = x;

最后一行代碼的原型是:
parking_lot[num_vehicles++] = VehicleSurrogate(x);
我們重載的賦值符 ‘=’ 的好處就出現(xiàn)了唾糯,使代碼變得更加簡潔明了怠硼。


最后,當(dāng)然要埋下伏筆啦移怯。什么伏筆呢香璃?
相信細(xì)心的讀者也發(fā)現(xiàn),涉及到代理就離不開復(fù)制芋酌,但是復(fù)制一個類的代價有時候是很大的增显,是我們不愿意的支付的,那我們?nèi)绾伪苊膺@些復(fù)制呢脐帝?希望讀者也能思考思考同云。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末忌警,一起剝皮案震驚了整個濱河市初坠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吁讨,老刑警劉巖疚顷,帶你破解...
    沈念sama閱讀 211,496評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旱易,死亡現(xiàn)場離奇詭異,居然都是意外死亡腿堤,警方通過查閱死者的電腦和手機(jī)阀坏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,187評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笆檀,“玉大人忌堂,你說我怎么就攤上這事⌒锶鳎” “怎么了士修?”我有些...
    開封第一講書人閱讀 157,091評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長樱衷。 經(jīng)常有香客問我棋嘲,道長,這世上最難降的妖魔是什么矩桂? 我笑而不...
    開封第一講書人閱讀 56,458評論 1 283
  • 正文 為了忘掉前任沸移,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雹锣。我一直安慰自己流妻,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,542評論 6 385
  • 文/花漫 我一把揭開白布笆制。 她就那樣靜靜地躺著绅这,像睡著了一般。 火紅的嫁衣襯著肌膚如雪在辆。 梳的紋絲不亂的頭發(fā)上证薇,一...
    開封第一講書人閱讀 49,802評論 1 290
  • 那天,我揣著相機(jī)與錄音匆篓,去河邊找鬼浑度。 笑死,一個胖子當(dāng)著我的面吹牛鸦概,可吹牛的內(nèi)容都是我干的箩张。 我是一名探鬼主播,決...
    沈念sama閱讀 38,945評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼窗市,長吁一口氣:“原來是場噩夢啊……” “哼先慷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咨察,我...
    開封第一講書人閱讀 37,709評論 0 266
  • 序言:老撾萬榮一對情侶失蹤论熙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摄狱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脓诡,經(jīng)...
    沈念sama閱讀 44,158評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,502評論 2 327
  • 正文 我和宋清朗相戀三年媒役,在試婚紗的時候發(fā)現(xiàn)自己被綠了祝谚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,637評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡酣衷,死狀恐怖交惯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸥诽,我是刑警寧澤商玫,帶...
    沈念sama閱讀 34,300評論 4 329
  • 正文 年R本政府宣布箕憾,位于F島的核電站牡借,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏袭异。R本人自食惡果不足惜钠龙,卻給世界環(huán)境...
    茶點故事閱讀 39,911評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碴里,春花似錦沈矿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,744評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至根竿,卻和暖如春陵像,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寇壳。 一陣腳步聲響...
    開封第一講書人閱讀 31,982評論 1 266
  • 我被黑心中介騙來泰國打工醒颖, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人壳炎。 一個月前我還...
    沈念sama閱讀 46,344評論 2 360
  • 正文 我出身青樓泞歉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匿辩。 傳聞我的和親對象是個殘疾皇子腰耙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,500評論 2 348

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

  • 今天翻出去年初寫的一篇競品分析,發(fā)上來做個紀(jì)念铲球!現(xiàn)在看看有很多不成熟的地方沟优,分析的思路也不足夠清晰。不過其中有一個...
    OD張閱讀 8,388評論 2 26
  • 停車產(chǎn)品市場趨勢與格局 互聯(lián)網(wǎng)對停車市場的改造已經(jīng)歷了很多年睬辐,但就目前而言挠阁,始終處于不溫不火的狀態(tài)。2010年前后...
    shxian閱讀 6,736評論 1 30
  • 領(lǐng)域驅(qū)動設(shè)計(DDD)旨在軟件設(shè)計過程中提煉領(lǐng)域模型溯饵,以領(lǐng)域模型為核心改善業(yè)務(wù)專家和軟件開發(fā)者的溝通方式侵俗,對企業(yè)級...
    MagicBowen閱讀 5,467評論 0 29
  • 1.dSYM你是如何分析的? 2.多線程有哪幾種丰刊?你更傾向于哪一種隘谣? 3.單例弊端? 4.如何把異步線程轉(zhuǎn)換成同步...
    xiaon閱讀 1,470評論 0 2