<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 4.3 類之間的關系(Relationships between classes) ### 友元函數(Friend functions) 在前面的章節中我們已經看到了對class的不同成員存在3個層次的內部保護:public, protected 和 private。在成員為 protected 和 private的情況下,它們不能夠被從所在的class以外的部分引用。然而,這個規則可以通過在一個class中使用關鍵字friend來繞過,這樣我們可以允許一個外部函數獲得訪問class的protected 和 private 成員的能力。 為了實現允許一個外部函數訪問class的private 和 protected 成員,我們必須在class內部用關鍵字friend來聲明該外部函數的原型,以指定允許該函數共享class的成員。在下面的例子中我們聲明了一個 friend 函數 duplicate: ~~~ // friend functions #include <iostream.h> class CRectangle { int width, height; public: void set_values (int, int); int area (void) {return (width * height);} friend CRectangle duplicate (CRectangle); }; void CRectangle::set_values (int a, int b) { width = a; height = b; } CRectangle duplicate (CRectangle rectparam) { CRectangle rectres; rectres.width = rectparam.width*2; rectres.height = rectparam.height*2; return (rectres); } int main () { CRectangle rect, rectb; rect.set_values (2,3); rectb = duplicate (rect); cout << rectb.area(); } ~~~ | 24 | 函數duplicate是CRectangle的friend,因此在該函數之內,我們可以訪問CRectangle 類型的各個object的成員 width 和 height。注意,在 duplicate()的聲明中,及其在后面main()里被調用的時候,我們并沒有把duplicate 當作class CRectangle的成員,它不是。 friend 函數可以被用來實現兩個不同class之間的操作。廣義來說,使用friend 函數是面向對象編程之外的方法,因此,如果可能,應盡量使用class的成員函數來完成這些操作。比如在以上的例子中,將函數duplicate() 集成在class CRectangle 可以使程序更短。 ### 友元類 (Friend classes) 就像我們可以定義一個friend 函數,我們也可以定義一個class是另一個的friend,以便允許第二個class訪問第一個class的 protected 和 private 成員。 ~~~ // friend class #include <iostream.h> class CSquare; class CRectangle { int width, height; public: int area (void) {return (width * height);} void convert (CSquare a); }; Class CSquare { private: int side; public: void set_side (int a){side=a;} friend class CRectangle; }; void CRectangle::convert (CSquare a) { width = a.side; height = a.side; } int main () { CSquare sqr; CRectangle rect; sqr.set_side(4); rect.convert(sqr); cout << rect.area(); return 0; } ~~~ | 16 | 在這個例子中,我們聲明了CRectangle 是CSquare 的friend,因此CRectangle可以訪問CSquare 的protected 和 private 成員,更具體地說,可以訪問CSquare::side,它定義了正方形的邊長。 在上面程序的第一個語句里你可能也看到了一些新的東西,就是class CSquare空原型。這是必需的,因為在CRectangle 的聲明中我們引用了CSquare (作為convert()的參數)。CSquare 的定義在CRectangle的后面,因此如果我們沒有在這個class之前包含一個CSquare 的聲明,它在CRectangle中就是不可見的。 這里要考慮到,如果沒有特別指明,友元關系(friendships)并不是相互的。在我們的CSquare 例子中,CRectangle 是一個friend類,但因為CRectangle 并沒有對CSquare作相應的聲明,因此CRectangle 可以訪問CSquare 的 protected 和private 成員,但反過來并不行,除非我們將 CSquare 也定義為CRectangle的 friend。 ### 類之間的繼承(Inheritance between classes) 類的一個重要特征是繼承,這使得我們可以基于一個類生成另一個類的對象,以便使后者擁有前者的某些成員,再加上它自己的一些成員。例如,假設我們要聲明一系列類型的多邊形,比如長方形CRectangle或三角形CTriangle。它們有一些共同的特征,比如都可以只用兩條邊來描述:高(height)和底(base)。 這個特點可以用一個類CPolygon 來表示,基于這個類我們可以引申出上面提到的兩個類CRectangle 和 CTriangle 。 ![](https://box.kancloud.cn/2015-09-06_55ebf3556787a.gif) 類CPolygon 包含所有多邊形共有的成員。在我們的例子里就是: width 和 height。而CRectangle 和 CTriangle 將為它的子類(derived classes)。 由其它類引申而來的子類繼承基類的所有可視成員,意思是說,如果一個基類包含成員A ,而我們將它引申為另一個包含成員B的類,則這個子類將同時包含 A 和 B。 要定義一個類的子類,我們必須在子類的聲明中使用冒號(colon)操作符: ,如下所示: `class derived_class_name: public base_class_name;` 這里derived_class_name 為子類(derived class)名稱,base_class_name 為基類(base class)名稱。public 也可以根據需要換為protected 或 private,描述了被繼承的成員的訪問權限,我們在以下例子后會很快看到: ~~~ // derived classes #include <iostream.h> Class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b;} }; class CRectangle: public CPolygon { public: int area (void){ return (width * height); } }; class CTriangle: public CPolygon { public: int area (void){ return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; rect.set_values (4,5); trgl.set_values (4,5); cout << rect.area() << endl; cout << trgl.area() << endl; return 0; } ~~~ | 20 10 | 如上所示,類 CRectangle 和 CTriangle 的每一個對象都包含CPolygon的成員,即: width, height 和 set_values()。 標識符protected 與 private類似,它們的唯一區別在繼承時才表現出來。當定義一個子類的時候,基類的protected 成員可以被子類的其它成員所使用,然而private 成員就不可以。因為我們希望CPolygon的成員width 和 height能夠被子類CRectangle 和 CTriangle 的成員所訪問,而不只是被CPolygon自身的成員操作,我們使用了protected 訪問權限,而不是 private。 下表按照誰能訪問總結了不同訪問權限類型: | 可以訪問 | public | protected | private | | 本class的成員 | yes | yes | yes | | 子類的成員 | yes | yes | no | | 非成員 | yes | no | no | 這里"非成員"指從class以外的任何地方引用,例如從main()中,從其它的class中或從全域(global)或本地(local)的任何函數中。 在我們的例子中,CRectangle 和CTriangle 繼承的成員與基類CPolygon擁有同樣的訪問限制: ~~~ CPolygon::width // protected access CRectangle::width // protected access CPolygon::set_values() // public access CRectangle::set_values() // public access ~~~ 這是因為我們在繼承的時候使用的是public,記得我們用的是: `class CRectangle: public CPolygon;` 這里關鍵字 public 表示新的類(CRectangle)從基類(CPolygon)所繼承的成員必須獲得最低程度保護。這種被繼承成員的訪問限制的最低程度可以通過使用 protected 或 private而不是public來改變。例如,daughter 是mother 的一個子類,我們可以這樣定義: `class daughter: protected mother;` 這將使得protected 成為daughter 從mother處繼承的成員的最低訪問限制。也就是說,原來mother 中的所有public 成員到daughter 中將會成為protected 成員,這是它們能夠被繼承的最低訪問限制。當然這并不是限制daughter 不能有它自己的public 成員。最低訪問權限限制只是建立在從mother中 繼承的成員上的。 最常用的繼承限制除了public 外就是private ,它被用來將基類完全封裝起來,因為在這種情況下,除了子類自身外,其它任何程序都不能訪問那些從基類繼承而來的成員。不過大多數情況下繼承都是使用public的。 如果沒有明確寫出訪問限制,所有由關鍵字class 生成的類被默認為private ,而所有由關鍵字struct 生成的類被默認為public。 ### 什么是從基類中繼承的? (What is inherited from the base class?) 理論上說,子類(drived class)繼承了基類(base class)的所有成員,除了: * 構造函數Constructor 和析構函數destructor * operator=() 成員 * friends 雖然基類的構造函數和析構函數沒有被繼承,但是當一個子類的object被生成或銷毀的時候,其基類的默認構造函數 (即,沒有任何參數的構造函數)和析構函數總是被自動調用的。 如果基類沒有默認構造函數,或你希望當子類生成新的object時,基類的某個重載的構造函數被調用,你需要在子類的每一個構造函數的定義中指定它: `derived_class_name (parameters) : base_class_name (parameters) {}` 例如 (注意程序中黑體的部分): ~~~ // constructors and derivated classes #include <iostream.h> class mother { public: mother () { cout << "mother: no parameters\n"; } mother (int a) { cout << "mother: int parameter\n"; } }; class daughter : public mother { public: daughter (int a) { cout << "daughter: int parameter\n\n"; } }; class son : public mother { public: son (int a) : mother (a) { cout << "son: int parameter\n\n"; } }; int main () { daughter cynthia (1); son daniel(1); return 0; } ~~~ | mother: no parameters daughter: int parameter mother: int parameter son: int parameter | 觀察當一個新的daughter object生成的時候mother的哪一個構造函數被調用了,而當新的son object生成的時候,又是哪一個被調用了。不同的構造函數被調用是因為daughter 和 son的構造函數的定義不同: ~~~ daughter (int a) // 沒有特別制定:調用默認constructor son (int a) : mother (a) // 指定了constructor: 調用被指定的構造函數 ~~~ ### 多重繼承(Multiple inheritance) 在C++ 中,一個class可以從多個class中繼承屬性或函數,只需要在子類的聲明中用逗號將不同基類分開就可以了。例如,如果我們有一個特殊的class COutput 可以實現向屏幕打印的功能,我們同時希望我們的類CRectangle 和 CTriangle 在CPolygon 之外還繼承一些其它的成員,我們可以這樣寫: `class CRectangle: public CPolygon, public COutput { class CTriangle: public CPolygon, public COutput {` 以下是一個完整的例子: ~~~ // multiple inheritance #include <iostream.h> class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b;} }; class COutput { public: void output (int i); }; void COutput::output (int i) { cout << i << endl; } class CRectangle: public CPolygon, public COutput { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon, public COutput { public: int area (void) { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; rect.set_values (4,5); trgl.set_values (4,5); rect.output (rect.area()); trgl.output (trgl.area()); return 0; } ~~~ |
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看