• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++多繼承中的二義性

            多繼承可以看作是單繼承的擴展。所謂多繼承是指派生類具有多個基類,派生類與每個基類之間的關系仍可看作是一個單繼承。

                多繼承下派生類的定義格式如下:

                class <派生類名>:<繼承方式1><基類名1>,<繼承方式2><基類名2>,…

                {

                <派生類類體>

                };

                其中,<繼承方式1>,<繼承方式2>,…是三種繼承方式:public、private、protected之一。例如:

                class A

                {

                …

                };

                class B

                {

                …

                };

                class C : public A, public B

                {

                …

                };

                其中,派生類C具有兩個基類(類A和類B),因此,類C是多繼承的。按照繼承的規定,派生類C的成員包含了基類A, B中成員以及該類本身的成員。

                多繼承的構造函數

                在多繼承的情況下,派生類的構造函數格式如下:

                <派生類名>(<總參數表>):<基類名1>(<參數表1>),<基類名2>(<參數表2>),…

                <子對象名>(<參數表n+1>),…

                {

                <派生類構造函數體>

                }

                其中,<總參數表>中各個參數包含了其后的各個分參數表。

                多繼承下派生類的構造函數與單繼承下派生類構造函數相似,它必須同時負責該派生類所有基類構造函數的調用。同時,派生類的參數個數必須包含完成所有基類初始化所需的參數個數。

                派生類構造函數執行順序是先執行所屬基類的構造函數,再執行派生類本身構造函數,處于同一層次的各基類構造函數的執行順序取決于定義派生類時所指定的各基類順序,與派生類構造函數中所定義的成員初始化列表的各項順序無關。也就是說,執行基類構造函數的順序取決于定義派生類時基類的順序??梢姡缮悩嬙旌瘮档某蓡T初始化列表中各項順序可以任意地排列。

                下面通過一個例子來說明派生類構造函數的構成及其執行順序。

                #include <iostream.h>

                class B1

                {

                public:

                B1(int i)

                {

                b1 = i;

                cout《"構造函數 B1."《i《 endl;

                }

                void print()

                {

                cout《"B1.print()"《b1《endl;

                }

                private:

                int b1;

                };

                class B2

                {

                public:

                B2(int i)

                {

                b2 = i;

                cout《"構造函數 B2."《i《 endl;

                }

                void print()

                {

                cout《"B2.print()"《b2《endl;

                }

                private:

                int b2;

                };

                class B3

                {

                public:

                B3(int i)

                {

                b3 = i;

                cout《"構造函數 B3."《i《endl;

                }

                int getb3()

                {

                return b3;

                }

                private:

                int b3;

                };

                class A : public B2, public B1

                {

                public:

                A(int i, int j, int k, int l):B1(i), B2(j), bb(k)

                {

                a = l;

                cout《"構造函數 A."《a《endl;

                }

                void print()

                {

                B1::print();

                B2::print();

                cout《"A.print()"《a《","《bb.getb3()《endl;

                }

                private:

                int a;

                B3 bb;

                };

                void main()

                {

                A aa(1, 2, 3, 4);

                aa.print();

                }


            該程序的輸出結果為:

                構造函數 B2.2

                構造函數 B1.1

                構造函數 B3.3

                構造函數 A.4

                B1.print()。1

                B2.print()2

                A.print()4, 3

                在該程序中,作用域運算符::用于解決作用域沖突的問題。在派生類A中的print()函數的定義中,使用了B1::print;和B2::print();語句分別指明調用哪一個類中的print()函數,這種用法應該學會。

                二義性問題

                一般說來,在派生類中對基類成員的訪問應該是唯一的,但是,由于多繼承情況下,可能造成對基類中某成員的訪問出現了不唯一的情況,則稱為對基類成員訪問的二義性問題。

                實際上,在上例已經出現過這一問題,回憶一下上例中,派生類A的兩基類B1和B2中都有一個成員函數print()。如果在派生類中訪問 print()函數,到底是哪一個基類的呢?于是出現了二義性。但是在上例中解決了這個問題,其辦法是通過作用域運算符::進行了限定。如果不加以限定,則會出現二義性問題。

                下面再舉一個簡單的例子,對二義性問題進行深入討論。例如:

                class A

                {

                public:

                void f();

                };

                class B

                {

                public:

                void f();

                void g();

                };

                class C : public A, public B

                {

                public:

                void g();

                void h();

                };

                如果定義一個類C的對象c1:

                C c1;

                則對函數f()的訪問

                c1.f();

                便具有二義性:是訪問類A中的f(),還是訪問類B中的f()呢?

                解決的方法可用前面用過的成員名限定法來消除二義性,例如:

                c1.A::f();

                或者

                c1.B::f();

                但是,最好的解決辦法是在類C中定義一個同名成員f(),類C中的f()再根據需要來決定調用A::f(),還是B::f(),還是兩者皆有,這樣,c1.f()將調用C::f()。

                同樣地,類C中成員函數調用f()也會出現二義性問題。例如:

                viod C::h()

                {

                f();

                }

                這里有二義性問題,該函數應修改為:

                void C::h()

                {

                A::f();

                }

                或者

                void C::h()

                {

                B::f();

                }

                或者

                void C::f()

                {

                A::f();

                B::f();

                }

                另外,在前例中,類B中有一個成員函數g(),類C中也有一個成員函數g()。這時,

                c1.g();

                不存在二義性,它是指C::g(),而不是指B::g()。因為這兩個g()函數,一個出現在基類B,一個出現在派生類C,規定派生類的成員將支配基類中的同名成員。因此,上例中類C中的g()支配類B中的g(),不存在二義性,可選擇支配者的那個名字。

                當一個派生類從多個基類派生類,而這些基類又有一個共同的基類,則對該基類中說明的成員進行訪問時,也可能會出現二義性。例如:

                class A

                {

                public:

                int a;

                };

                class B1 : public A

                {

                private:

                int b1;

                };

                class B2 : public A

                {

                private:

                int b2;

                };

                class C : public B1, public B2

                {

                public:

                int f();

                private:

                int c;

                };

                已知:C c1;

                下面的兩個訪問都有二義性:

                c1.a;

                c1.A::a;

                而下面的兩個訪問是正確的:

                c1.B1::a;

                c1.B2::a;

                類C的成員函數f()用如下定義可以消除二義性:

                int C::f()

                {

                retrun B1::a + B2::a;

                }

                由于二義性的原因,一個類不可以從同一個類中直接繼承一次以上,例如:

                class A : public B, public B

                {

                …

                }

                這是錯誤的。

            posted on 2012-03-20 22:31 一葉草 閱讀(543) 評論(0)  編輯 收藏 引用
            精品午夜久久福利大片| 一本一道久久a久久精品综合 | 久久这里只有精品首页| 久久91精品国产91久久户| 久久99精品久久久久久噜噜| 久久久噜噜噜久久中文字幕色伊伊| 国产精品久久久久a影院| 乱亲女H秽乱长久久久| 成人精品一区二区久久| 亚洲欧美伊人久久综合一区二区| 免费国产99久久久香蕉| 7777精品久久久大香线蕉| 国产精品久久久久久久午夜片 | 久久AV高潮AV无码AV| 97久久国产亚洲精品超碰热| 久久人搡人人玩人妻精品首页| 一本久久a久久精品vr综合| 久久久久久极精品久久久| 无遮挡粉嫩小泬久久久久久久 | 国产一级做a爰片久久毛片| 国产精品久久久久久久久软件| 国产999精品久久久久久| 亚洲AV成人无码久久精品老人| 日韩电影久久久被窝网| 国产免费福利体检区久久| 国产成人精品久久免费动漫| 色综合久久无码中文字幕| 亚洲欧美国产精品专区久久| 香港aa三级久久三级老师2021国产三级精品三级在 | 久久久久人妻一区精品色| 伊人 久久 精品| 久久久久亚洲精品无码网址| 久久精品一区二区| 久久精品视频免费| 久久久久久久99精品免费观看| 久久精品黄AA片一区二区三区| 18岁日韩内射颜射午夜久久成人| 人人狠狠综合久久亚洲高清| 精品久久久久久99人妻| 要久久爱在线免费观看| 无码人妻久久一区二区三区蜜桃 |