C++基础知识(二)
八、
? ? ? 繼承:讓某個(gè)類的對(duì)象獲得另一個(gè)類的對(duì)象的特性。通過繼承可實(shí)現(xiàn)代碼重用,即從已存在的類派生出的一個(gè)新類將自動(dòng)具有原來那個(gè)類的特性。
? ? ? 類的繼承還具有:(1)單向性;A類為B類的基類(父類),則派生類(子類)B繼承了父類A中的屬性和方法,在B類中可訪問A類的屬性和方法,但在父類A中則不能訪問子類的任何屬性和方法。同時(shí)單向又體現(xiàn)為子類B繼承了父類A,則A類不能再繼承B類。(2)傳遞性;A類為B類的基類,B類為C類的基類,則基類A中的屬性和方法通過子類B同時(shí)又傳給了子類C,同理C類也不能作為A類的基類。(3)可重用性;通過繼承,基類代碼得到重用,而不用重寫。
? ? ??C++規(guī)定派生類中對(duì)象成員(其它類的對(duì)象)初值的設(shè)定應(yīng)在初始化列表中進(jìn)行,所以派生類的構(gòu)造函數(shù)定義(派生類頭文件中構(gòu)造函數(shù)的聲明格式與普通類相同)可寫成:函數(shù)類型 派生類名::派生類名(形參表):基類1(參數(shù)表),基類2(參數(shù)表),...,基類n(參數(shù)表),對(duì)象成員1(參數(shù)表),對(duì)象成員2(參數(shù)表),...,對(duì)象成員n(參數(shù)表) {...}
? ? ? 在派生類數(shù)據(jù)成員通常有3類:繼承于基類的數(shù)據(jù)成員,派生類中自身定義的數(shù)據(jù)成員以及派生類中其它類的對(duì)象。在上述形式中,由于基類在派生類中常常是隱常的,所以通過調(diào)用基類構(gòu)造函數(shù)來對(duì)基類的數(shù)據(jù)成員初值化,這也稱為基類拷貝或基類子對(duì)象。在上述構(gòu)造函數(shù)定義中的對(duì)象成員為派生類中定義的其它類的對(duì)象(構(gòu)造函數(shù)中的形參初始化)。
? ? ??當(dāng)然在初始化列表中也可對(duì)派生類自身數(shù)據(jù)成員初始化,但必須為“數(shù)據(jù)成員名(參數(shù)表)”形式。對(duì)于基類拷貝成員的初始化次序,若為單繼承,優(yōu)先初始化上層類的對(duì)象;若為多繼承,則取決于派生類聲明指定繼承時(shí)的基類的先后次序,與初始化列表中的次序無關(guān)。對(duì)于派生類自身數(shù)據(jù)成員的初始化次序與初始化列表中的次序無關(guān),取決于在派生類中聲明的先后次序。
繼承方式:公有繼承(public),私有繼承(private),保護(hù)繼承(protected)。
公有繼承:
? ? ? ?基類對(duì)象可訪問基類公有成員,不可訪問保護(hù)成員和私有成員。
? ? ? ?派生類成員可訪問基類的公有成員和保護(hù)成員,它們作為派生類的成員時(shí),保持原來的狀態(tài);若在派生類中有同名成員存在,則訪問基類成員時(shí),基類成員名前面必須加上“基類名::”來指定成員所屬的類;派生類成員不可訪問基類的私有成員。
? ? ? ?派生類對(duì)象只能訪問基類的公有成員,不可訪問保護(hù)成員和私有成員;對(duì)于同名成員,在基類成員名前面加上“基類名::”來指定成員所屬的類,如OB.OA::m或OB-> OA::m。
? ? ? ?總之,公有繼承時(shí),基類對(duì)象與派生類對(duì)象可訪問基類的公有成員,而派生類的成員函數(shù)則可訪問基類的公有成員和保護(hù)成員。
私有繼承:
? ? ? ?基類對(duì)象可訪問基類公有成員,不可訪問保護(hù)成員和私有成員。
? ? ? ?派生類成員可訪問基類的公有成員和保護(hù)成員,它們作為派生類的成員時(shí),作為派生類的私有成員,因此不能被這個(gè)派生類的子類所訪問;若在派生類中有同名成員存在,則訪問基類成員時(shí)基類成員名前面必須加上“基類名::”來指定成員所屬的類;派生類成員不可訪問基類的私有成員。
? ? ? ?派生類對(duì)象不能訪問基類任何成員(公有成員也不能訪問)。
? ? ? ?總之,私有繼承時(shí),基類對(duì)象可訪問基類公有成員,派生類對(duì)象不能訪問基類所有成員,而派生類的成員函數(shù)則可訪問基類的公有成員和保護(hù)成員(但不能再往下繼承)。
保護(hù)繼承:
? ? ? ?基類對(duì)象可訪問基類公有成員,不可訪問保護(hù)成員和私有成員。
? ? ? ?派生類成員可訪問基類的公有成員和保護(hù)成員,它們作為派生類的成員時(shí),作為派生類的保護(hù)成員(與私有繼承的唯一區(qū)別),且不能被這個(gè)派生類的子類所訪問;若在派生類中有同名成員存在,則訪問基類成員時(shí)基類成員名前面必須加上“基類名::”來指定成員所屬的類;派生類成員不可訪問基類的私有成員。
? ? ? ?派生類對(duì)象不能訪問基類任何成員(公有成員也不能訪問)。
? ? ? ?總之,保護(hù)繼承時(shí),基類對(duì)象可訪問基類公有成員,派生類對(duì)象不能訪問基類所有成員,而派生類的成員函數(shù)則可訪問基類的公有成員和保護(hù)成員(但不能再往下繼承)。
多重繼承與虛繼承:虛繼承是為解決多重繼承而出現(xiàn)的,是多重繼承中特有的概念。例如,類D繼承于類B和類C,而類B和類C又都繼承于類A,即A類是B類和C類的基類,而B類和C類同時(shí)是D類的基類。為了節(jié)省內(nèi)存空間 ,可以將B,C對(duì)A的繼承定義為虛擬繼承,則A就成了虛擬基類。用代碼表示如下:
? class A ;
? class B:public virtual A;//虛擬繼承
? class C:public virtual A;//虛擬繼承
? class D:public B,public C;
??最后說明,在面向?qū)ο蟮某绦蛟O(shè)計(jì)中,繼承和多重繼承一般是指公共繼承,很少用私有繼承和保護(hù)繼承。
九、
? ? 多態(tài):允許將子類類型的指針賦值給父類類型的指針。多態(tài)性是通過虛函數(shù)實(shí)現(xiàn)的,是面向?qū)ο缶幊痰暮诵母拍睢L摵瘮?shù)就是允許被其子類重新定義的成員函數(shù),而子類重新定義父類虛函數(shù)的做法,叫做覆蓋或重寫。
? ??覆蓋是指子類重新定義父類的虛函數(shù)的做法。重寫的函數(shù)必須有一致的參數(shù)表和返回值(C++標(biāo)準(zhǔn)允許返回值不同的情況,但很少有編譯器支持)。
? ??重載是指編寫一個(gè)與已有函數(shù)同名但參數(shù)表不同(個(gè)數(shù)或類型不同)的函數(shù)。即指允許存在多個(gè)同名函數(shù), 但這些函數(shù)的參數(shù)表不同。重載的概念并不屬于面向?qū)ο缶幊?/span>。它的實(shí)現(xiàn)是:編譯器根據(jù)函數(shù)不同的參數(shù)表,對(duì)同名函數(shù)的名稱做修飾,然后這些同名函數(shù)就成了不同的函數(shù)(至少對(duì)編譯器來說是這樣的)。函數(shù)重載是靜態(tài)聯(lián)編的具體實(shí)現(xiàn)方式。調(diào)用重載函數(shù)時(shí),編譯根據(jù)調(diào)用時(shí)參數(shù)類型與個(gè)數(shù)在編譯時(shí)實(shí)現(xiàn)靜態(tài)聯(lián)編,將調(diào)用地址與函數(shù)名進(jìn)行綁定。所以說對(duì)于重載函數(shù)的調(diào)用,在編譯期間就確定了,是靜態(tài)的,也就是說它們的函數(shù)標(biāo)識(shí)符與內(nèi)存地址在編譯期就綁定了(早綁定)。因此重載與多態(tài)無關(guān)。
? ? ? 在靜態(tài)聯(lián)編的方式下,同一成員函數(shù)(參數(shù)類型及個(gè)數(shù)相同,函數(shù)返回類型也相同)在基類與派生類中的不同版本是不會(huì)在運(yùn)行時(shí)根據(jù)程序代碼的指定進(jìn)行自動(dòng)綁定的,必須通過類的虛函數(shù)機(jī)制,才能實(shí)現(xiàn)基類和派生類中的成員函數(shù)不同版本的動(dòng)態(tài)聯(lián)編。動(dòng)態(tài)聯(lián)編是指函數(shù)標(biāo)識(shí)符與內(nèi)存地址在程序運(yùn)行時(shí)動(dòng)態(tài)綁定,而不在編譯時(shí)靜態(tài)綁定,所以又稱晚綁定。虛函數(shù)是用關(guān)鍵字virtual來修飾基類中的public或protected的成員函數(shù)。當(dāng)在派生類中進(jìn)行重新定義后(函數(shù)覆蓋),就可在此派生類中具有該成員函數(shù)的不同版本。在程序運(yùn)行過程中,依據(jù)基類對(duì)象指針?biāo)赶虻呐缮悓?duì)象,或通過基類引用對(duì)象所引用的派生類對(duì)象,才能確定哪個(gè)派生類中重新定義的成員函數(shù)被激活,從而實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編。虛函數(shù)雖然只是在一般函數(shù)定義前加上virtual,但必須是類中成員函數(shù);可把析構(gòu)函數(shù)定義為虛函數(shù),但不能把構(gòu)造函數(shù)定義為虛函數(shù),通常在釋放基類中及其派生類中動(dòng)態(tài)申請(qǐng)的存儲(chǔ)空間時(shí),也要把析構(gòu)函數(shù)定義為虛函數(shù),以便實(shí)現(xiàn)撤銷對(duì)象時(shí)的多態(tài)性;虛函數(shù)在派生類重新定義時(shí),參數(shù)個(gè)數(shù)和類型以及函數(shù)類型必須和基類的虛函數(shù)完全匹配,這一點(diǎn)與函數(shù)重載完全不同;虛函數(shù)派生下去仍是虛函數(shù),且可省略virtual關(guān)鍵字。
? ? 當(dāng)子類重新定義了父類的虛函數(shù)后,父類指針根據(jù)賦給它的不同的子類指針,動(dòng)態(tài)地調(diào)用屬于子類的該函數(shù),這樣的函數(shù)調(diào)用在編譯期間是無法確定的(所調(diào)子類的虛函數(shù)的地址無法確定)。因此,這樣的函數(shù)地址是在函數(shù)運(yùn)行期間綁定的(晚綁定)。
? ? 基類與派生類中的每個(gè)虛函數(shù)都在虛函數(shù)表中(vtable)占有一個(gè)表項(xiàng),保存著一條跳轉(zhuǎn)到它的入口地址的指令(實(shí)際上就是保存它的入口地址)。當(dāng)一個(gè)包含虛函數(shù)的對(duì)象(注意,不是指針類型對(duì)象)被創(chuàng)建時(shí),它在頭部附加一個(gè)指針,指向vtable中相應(yīng)的位置。調(diào)用虛函數(shù)的時(shí)候,不管是用什么指針調(diào)用的,它先根據(jù) vtable找到入口地址再執(zhí)行,從而實(shí)現(xiàn)了動(dòng)態(tài)聯(lián)編。而普通函數(shù)只有簡單地跳轉(zhuǎn)到一個(gè)固定的地址。
十、
? ? 只有類的成員函數(shù)才能訪問類的私有成員,程序中的其它函數(shù)是無法訪問私有成員的。非成員函數(shù)可以訪問類中的公有成員,不能訪問其私有成員。
? ? 友元是一種定義在類外部的普通函數(shù),但它需要在類中說明,為了與該類的成員函數(shù)加以區(qū)別,在說明時(shí)前面加以關(guān)鍵字friend。友元不是成員函數(shù),但它可以訪問類中的私有成員。友元可以提高程序的運(yùn)行效率。但是它破壞了類的封裝性和隱藏性,使非成員函數(shù)也可以訪問類的私有成員。友元可以是一個(gè)函數(shù),稱為友元函數(shù);友元也可以是一個(gè)類,稱為友元類。
十一、
? ? ?this指針:this指針是類中一個(gè)特殊指針,當(dāng)類實(shí)例化(用類定義對(duì)象)時(shí),this指針指向?qū)ο笞约?#xff0c;而在類的聲明時(shí)指向類本身。
十二、
? ? 關(guān)于C++中class里面 static變量問題(即面向?qū)ο蟮某绦蛟O(shè)計(jì)中的static),與C中的static全局變量和局部變量含義不同(C是面向過程的程序設(shè)計(jì))
??class B:?
? {
? ?public:
? ? static int a;
? };
? B b;
? int _tmain(int argc, _TCHAR* argv[])
? {
? ? ?b.a = 10;
? ? ?system("pause");
? ? ?return 0;
? }
? ?編譯出現(xiàn)錯(cuò)誤:
? ?Error error LNK2001: unresolved external symbol "public: static int B::a"?
? ??解決方法:必須初始化,初始化的時(shí)候要在類外;如下:添加int B::a = 0;也可在類中初始化,在類中寫成static int a=0; ? ? ?
? ? 靜態(tài)變量是屬于類,而不是屬于類對(duì)象的。也就是說不管你有多少個(gè)類對(duì)象,靜態(tài)成員只有一個(gè)。?它的初始化,不能依賴于創(chuàng)建類對(duì)象時(shí)用于初始化對(duì)象的構(gòu)造函數(shù)。
? ? 靜態(tài)數(shù)據(jù)成員也遵從 public/private/protected訪問規(guī)則。類中的那個(gè)static int a; 只是聲明,定義要放在外面int B::a = 0; // 此處可以初始化?。如果a是公有的,B::a就可以訪問了(讀取和修改)。?靜態(tài)成員的提出是為了解決數(shù)據(jù)共享的問題。實(shí)現(xiàn)共享有許多方法,如:設(shè)置全局性的變量或?qū)ο笫且环N方法。但是,全局變量或?qū)ο笫怯芯窒扌缘?。在類?#xff0c;靜態(tài)成員可以實(shí)現(xiàn)多個(gè)對(duì)象之間的數(shù)據(jù)共享,并且使用靜態(tài)數(shù)據(jù)成員還不會(huì)破壞隱藏的原則,即保證了安全性。因此,靜態(tài)成員是類的所有對(duì)象中共享的成員,而不是某個(gè)對(duì)象的成員。
?使用靜態(tài)數(shù)據(jù)成員可以節(jié)省內(nèi)存,因?yàn)樗撬袑?duì)象所公有的。對(duì)該類的多個(gè)對(duì)象來說,靜態(tài)數(shù)據(jù)成員只分配一次內(nèi)存,供所有對(duì)象共用。因此,對(duì)多個(gè)對(duì)象來說,靜態(tài)數(shù)據(jù)成員只存儲(chǔ)一處,供所有對(duì)象共用。靜態(tài)數(shù)據(jù)成員的值對(duì)每個(gè)對(duì)象都是一樣,但它的值是可以更新的。只要對(duì)靜態(tài)數(shù)據(jù)成員的值更新一次,保證所有對(duì)象存取更新后的相同的值,這樣可以提高時(shí)間效率。因?yàn)殪o態(tài)數(shù)據(jù)成員在全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存,屬于本類的所有對(duì)象共享,所以,它不屬于特定的類對(duì)象,在沒有產(chǎn)生類對(duì)象時(shí)其作用域就可見,即在沒有產(chǎn)生類的實(shí)例時(shí),我們就可以操作它;
? ? ? 同全局變量相比,使用靜態(tài)數(shù)據(jù)成員有兩個(gè)優(yōu)勢(shì):靜態(tài)數(shù)據(jù)成員沒有進(jìn)入程序的全局名字空間,因此不存在與程序中其它全局名字沖突的可能性;可以實(shí)現(xiàn)信息隱藏,靜態(tài)數(shù)據(jù)成員可以是private成員,而全局變量不能;
靜態(tài)數(shù)據(jù)成員的使用方法和注意事項(xiàng)如下:
1、靜態(tài)數(shù)據(jù)成員在定義或說明時(shí)前面加關(guān)鍵字static。
2、靜態(tài)成員初始化與一般數(shù)據(jù)成員初始化不同。靜態(tài)數(shù)據(jù)成員初始化的格式如下:
<數(shù)據(jù)類型><類名>::<靜態(tài)數(shù)據(jù)成員名>=<值>
這表明:
? ? ? (1) 初始化可在類外進(jìn)行,而前面不加static,以免與一般靜態(tài)變量或?qū)ο笙嗷煜?。?dāng)然也可在類中初始化。
(2) 初始化時(shí)不加該成員的訪問權(quán)限控制符private,public等。
(3) 初始化時(shí)使用作用域運(yùn)算符來標(biāo)明它所屬類,因此,靜態(tài)數(shù)據(jù)成員是類的成員,而不是對(duì)象的成員。
3、靜態(tài)數(shù)據(jù)成員是靜態(tài)存儲(chǔ)的,它是靜態(tài)生存期,必須對(duì)它進(jìn)行初始化。
4、引用靜態(tài)數(shù)據(jù)成員時(shí),采用如下格式:<類名>::<靜態(tài)成員名>
? ? ? 如果靜態(tài)數(shù)據(jù)成員的訪問權(quán)限允許的話(即public的成員),可在程序中,按上述格式來引用靜態(tài)數(shù)據(jù)成員。
?
? ? ?與靜態(tài)數(shù)據(jù)成員一樣,我們也可以創(chuàng)建一個(gè)靜態(tài)成員函數(shù),它為類的全部服務(wù)而不是為某一個(gè)類的具體對(duì)象服務(wù)。靜態(tài)成員函數(shù)與靜態(tài)數(shù)據(jù)成員一樣,都是類的內(nèi)部實(shí)現(xiàn),屬于類定義的一部分。普通的成員函數(shù)一般都隱含了一個(gè)this指針,this指針指向類的對(duì)象本身,因?yàn)槠胀ǔ蓡T函數(shù)總是具體的屬于某個(gè)類的具體對(duì)象的。通常情況下,this 是缺省的。如函數(shù)fn()實(shí)際上是this->fn()。但是與普通函數(shù)相比,靜態(tài)成員函數(shù)由于不是與任何的對(duì)象相聯(lián)系,因此它不具有this指針。從這個(gè)意義上講,它無法訪問屬于類對(duì)象的非靜態(tài)數(shù)據(jù)成員,也無法訪問非靜態(tài)成員函數(shù),它只能調(diào)用其余的靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員。而非靜態(tài)成員函數(shù)(普通函數(shù))可以訪問靜態(tài)數(shù)據(jù)成員和調(diào)用其余的靜態(tài)成員函數(shù)。
關(guān)于靜態(tài)成員函數(shù),可以總結(jié)為以下幾點(diǎn):
1、出現(xiàn)在類體外的函數(shù)定義不能指定關(guān)鍵字static;
2、靜態(tài)成員之間可以相互訪問,包括靜態(tài)成員函數(shù)訪問靜態(tài)數(shù)據(jù)成員和訪問靜態(tài)成員函數(shù);
3、非靜態(tài)成員函數(shù)可以任意地訪問靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員;
4、靜態(tài)成員函數(shù)不能訪問非靜態(tài)成員函數(shù)和非靜態(tài)數(shù)據(jù)成員;
5、由于沒有this指針的額外開銷,因此靜態(tài)成員函數(shù)與類的全局函數(shù)相比速度上會(huì)有少許的增長;
6、調(diào)用靜態(tài)成員函數(shù),可以用成員訪問操作符(.)和(->)為一個(gè)類的對(duì)象或指向類對(duì)象的指針調(diào)用靜態(tài)成員函數(shù),
? ? ?也可以直接使用如下格式:<類名>::<靜態(tài)成員函數(shù)名>(<參數(shù)表>)調(diào)用類的靜態(tài)成員函數(shù)。
轉(zhuǎn)載于:https://www.cnblogs.com/King-Gentleman/p/4822425.html
總結(jié)
以上是生活随笔為你收集整理的C++基础知识(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Qt 学习之路:模型-视图高级技术
- 下一篇: Entity Framework学习三: