面向?qū)ο缶幊毯驮O(shè)計

Object Oriented Programming and Object Oriented Design(面向?qū)ο缶幊毯驮O(shè)計)

本章內(nèi)容:
1 組合與繼承
2 虛函數(shù)與多態(tài)
3 委托相關(guān)設(shè)計


1 組合與繼承

  • 在該節(jié)中包含了三種關(guān)系:
    (1). Composition(復(fù)合)
    (2). Delegation(委托)
    (3). Inheritance(繼承)
(1) Composition(復(fù)合)
  • 復(fù)合表示has-a關(guān)系,例如queue包含deque,代碼如下所示:
has-a關(guān)系圖
  • 復(fù)合關(guān)系下的構(gòu)造和析構(gòu),下圖中Container包含Component台谊,UML圖和對象結(jié)構(gòu)圖如下所示:

    UML和對象結(jié)構(gòu)圖

  • 構(gòu)造由內(nèi)而外:

  • Container的構(gòu)造函數(shù)首先調(diào)用Componentdefault構(gòu)造函數(shù)剔宪,然后再執(zhí)行自己的構(gòu)造函數(shù)拘悦,如下所示:

      Container::Container(...) : Component() {...}
    
  • 其中Component()是編譯器默認(rèn)添加上去的低零。

  • 析構(gòu)由外而內(nèi):

  • Container的析構(gòu)函數(shù)首先執(zhí)行自己的析構(gòu)函數(shù),然后再調(diào)用Component的析構(gòu)函數(shù)姥宝,如下所示:

      Container::~Container(...)  {... ~Component(); }
    
  • 其中~Component()是編譯器默認(rèn)添加上去的。

(2) Delegation(委托)
  • 委托可以用Composition by reference表示恐疲,其中Composition by reference在這表示指針的意思腊满,UML圖如下所示:


    Delegation(委托)
  • 經(jīng)典的pImpl(point to implement)或Handle/Body模式,如下代碼所示:

      class StringRep;
      class String {
      public:
              String();
              String(const char* s);
              String(const String& s);
              String& operator=(const String& s);
              ~String();
      ......
      private:
              StringRep* rep;    // pImpl
      };
      class StringRep {
      public:
              friend class String;
              StringRep(const char* s);
              ~StringRep();
      private:
              int count;
              char* rep;
      };
      String::String() { ... }
      ......
    
  • 這個pImpl俗稱“編譯防火墻”培己,其可以用一個指針指向一個類碳蛋,StringRep類實(shí)現(xiàn)了具體的方法功能,String類只調(diào)用StringRep類的指針來實(shí)現(xiàn)其定義的接口漱凝,如此一來對外接口可以保持不變疮蹦,而具體的實(shí)現(xiàn)部分可以根據(jù)實(shí)際要求來用不同的方式實(shí)現(xiàn),從而達(dá)到了接口和實(shí)現(xiàn)隔離的效果茸炒。

(3) Inheritance(繼承)
  • 繼承表示is-a關(guān)系愕乎,如下圖表示:

    is-a關(guān)系圖

  • 繼承關(guān)系下的構(gòu)造和析構(gòu):


    UML和對象結(jié)構(gòu)圖
  • 構(gòu)造由內(nèi)而外:

  • Derived的構(gòu)造函數(shù)首先調(diào)用Basedefaule構(gòu)造函數(shù)阵苇,然后再執(zhí)行自己的構(gòu)造函數(shù),如下代碼所示:

              Derived::Derived(...) : Base() { ... }
    
  • 其中Base()是編譯器默認(rèn)添加上去的感论。

  • 析構(gòu)由外而內(nèi):

  • Derived的析構(gòu)函數(shù)首先執(zhí)行自己的構(gòu)造函數(shù)绅项,然后再調(diào)用Base的析構(gòu)函數(shù),如下代碼所示:

              Derived::Derived(...)  { ... ~Base() }
    
  • 其中~Base()是編譯器默認(rèn)添加上去的比肄。
    注意:base classdestructor必須是virual的快耿,否則會造成內(nèi)存泄漏或其他沒有定義的行為。

2 虛函數(shù)與多態(tài)

  • Inheritance(繼承) with virtual functions(虛函數(shù))
    (1). non-virtual函數(shù):你不希望derived class重新定義(override芳绩,覆寫)它掀亥。
    (2). virtual函數(shù):你希望derived class重新定義(override,覆寫)它妥色,且你對它已有默認(rèn)定義搪花。
    (3). pure virtual函數(shù):你希望derived class一定要重新定義(override,覆寫)它嘹害,你對它沒有默認(rèn)定義撮竿。

  • 三種functions的代碼表示方式如下圖:

    virtual functions虛函數(shù)

  • Inheritance+Composition關(guān)系下的構(gòu)造和析構(gòu)
    (1) Derived has a Component & Derived is a Base,UML圖如下所示:


    UML圖
  • 構(gòu)造由內(nèi)而外:

  • Derived的構(gòu)造函數(shù)首先調(diào)用Basedefault構(gòu)造函數(shù)笔呀,然后調(diào)用Component的構(gòu)造函數(shù)幢踏,最后執(zhí)行自己的構(gòu)造函數(shù)。

  • 析構(gòu)由外而內(nèi):

  • Derived的析構(gòu)函數(shù)首先執(zhí)行自己的構(gòu)造函數(shù)许师,然后調(diào)用Component的析構(gòu)函數(shù)房蝉,最后調(diào)用Base的析構(gòu)函數(shù)。

    (2) Derived is a Base & Base has a Component枯跑,UML圖如下所示:


    UML圖
  • 構(gòu)造由內(nèi)而外:

  • Derived的構(gòu)造函數(shù)首先調(diào)用Component的構(gòu)造函數(shù)惨驶,然后調(diào)用Basedefault構(gòu)造函數(shù),最后執(zhí)行自己的構(gòu)造函數(shù)敛助。

  • 析構(gòu)由外而內(nèi):

  • Derived的析構(gòu)函數(shù)首先執(zhí)行自己的構(gòu)造函數(shù)粗卜,然后調(diào)用Base的析構(gòu)函數(shù),最后調(diào)用Component的析構(gòu)函數(shù)纳击。

3 委托相關(guān)設(shè)計

  • Delegation(委托)+Inheritance(繼承)

  • 委托+繼承的用法之Observe(觀察者)模式续扔,UML圖如下所示:

    觀察者模式UML圖

  • 具體代碼示例如下:

      class Observer
      {
      public:
          virtual void update(int value) = 0;
      };
      class Subject
      {
      private:
          int m_value;
          vector<Observer*> m_views;
      public:
          void attach(Observer* obs)
          {
              m_views.push_back(obs);
          }
          void set_val(int value)
          {
              m_value = value;
              notify();
          }
          void notify()
          {
              for (int i=0;i<m_views.size();i++)
              {
                  m_views[i]->update(m_value);
              }
          }
      };
              // 繼承觀察者類
      class Observer1 : public Observer
      {
      private:
          int m_div;
      public:
          Observer1(Subject* model, int div)
          {
              model->attach(this);
              m_div = div;
          }
          void update(int v)
          { ... }
      };
      class Observer2 : public Observer
      {
      private:
          int m_mod;
      public:
          Observer2(Subject* model, int mod)
          {
              model->attach(this);
              m_mod= mod;
          }
          void update(int v)
          { ... }
      };
      // 使用詳解
      int main(void)
      {
          Subject subj;
          Observer1 o1(&subj, 4);
          Observer1 o2(&subj, 3);
          Observer2 o3(&subj, 3);
          subj.o1(14);
      }
    
  • (2) 委托+繼承的用法之Composite(組合)模式,UML圖如下所示:

    組合模式UML圖

  • 具體代碼示例如下:

      class Component
      {
      private:
          int value;
      public:
          Component(int val) 
          {
              value = val;
          }
          virtual void add(Component*) {}
      };
      class Composite : public Component
      {
      private:
          vector<Component*> c;
      public:
          Composite(int val) : Component(val) {}
          void add(Component* elem)
          {
              c.push_back(elem);
          }
          ......
      };
      class Primitive : public Component
      {
      public:
          Primitive(int val) : Component(val) {}
      };
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焕数,一起剝皮案震驚了整個濱河市纱昧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌堡赔,老刑警劉巖识脆,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡灼捂,警方通過查閱死者的電腦和手機(jī)离例,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悉稠,“玉大人宫蛆,你說我怎么就攤上這事〉拿停” “怎么了耀盗?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長卦尊。 經(jīng)常有香客問我叛拷,道長,這世上最難降的妖魔是什么猫牡? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任胡诗,我火速辦了婚禮,結(jié)果婚禮上淌友,老公的妹妹穿的比我還像新娘。我一直安慰自己骇陈,他們只是感情好震庭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著你雌,像睡著了一般器联。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婿崭,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天拨拓,我揣著相機(jī)與錄音,去河邊找鬼氓栈。 笑死渣磷,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的授瘦。 我是一名探鬼主播醋界,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼提完!你這毒婦竟也來了形纺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤徒欣,失蹤者是張志新(化名)和其女友劉穎容诬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涵叮,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年秽澳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戏羽。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡担神,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出始花,到底是詐尸還是另有隱情妄讯,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布酷宵,位于F島的核電站亥贸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏浇垦。R本人自食惡果不足惜炕置,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望男韧。 院中可真熱鬧朴摊,春花似錦、人聲如沸此虑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朦前。三九已至介杆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間韭寸,已是汗流浹背春哨。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恩伺,地道東北人赴背。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像莫其,于是被迫代替她去往敵國和親癞尚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

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