面向?qū)ο蟪绦蛟O(shè)計(jì)的核心思想是:
數(shù)據(jù)抽象:實(shí)現(xiàn)類與接口的分離。
繼承:定義相似類型并進(jìn)行相似關(guān)系建模。通過(guò)繼承聯(lián)系在一起的類構(gòu)成一種層次關(guān)系。通常在在層次關(guān)系的根部有一個(gè)基類,其他類直接或間接由基類繼承而來(lái)。這些繼承的類稱為派生類。基類負(fù)責(zé)定義在層次關(guān)系中所有類共同擁有的成員,而每個(gè)派生類定義各自特有的成員。對(duì)于某些函數(shù),基類希望它的派生類各自定義適合自身的版本,此時(shí)的基類就將這些函數(shù)聲明成虛函數(shù)。
class Quote{public: std::string isbn() const; virtual double net_PRice(std::size_t n) const;};派生類必須使用派生列表,必須將其繼承而來(lái)的成員函數(shù)中需要覆蓋的那些重新聲明:
class Bulk_Quote : public Quote//Bulj_Quote繼承了Quote{ double net_price(std::size_t n) const override;};動(dòng)態(tài)綁定:一定程序忽略相似類型的區(qū)別,而以統(tǒng)一的方式使用他們的對(duì)象。 在C++語(yǔ)言中,當(dāng)我們使用基類引用或指針調(diào)用一個(gè)虛函數(shù)將發(fā)生動(dòng)態(tài)綁定。
double print_total(ostream &os, const A &item,size_t n){ double ret=item.net_price(n);//根據(jù)傳入的item的對(duì)象類型調(diào)用Quote::net_price,還是Bulk_Quote::net_price return ret;}一個(gè)派生類對(duì)象包含多個(gè)組成部分:一個(gè)含有派生類自己定義的(非靜態(tài))成員的子對(duì)象,以及一個(gè)與該派生類繼承的基類的子對(duì)象。因?yàn)樵谂缮悓?duì)象中含有與其基類對(duì)應(yīng)的組成部分,所以我們能把派生類的對(duì)象當(dāng)成基類對(duì)象來(lái)使用,而且我們也能把基類的指針或引用綁定到派生類對(duì)象中的基類部分上。
Quote item;//基類對(duì)象Bulk_Quote bulk;//派生類對(duì)象Quote *p=&item;//p指向基類對(duì)象p=&bulk;//p指向派生類對(duì)象的基類部分Quote &r=bulk;//r綁定到派生類對(duì)象的基類部分Quote類的定義:
派生類Bulk_Quote定義;
派生類對(duì)象的基類部分與派生類對(duì)象自己的數(shù)據(jù)成員都是在構(gòu)造函數(shù)的初始化階段執(zhí)行初始化操作的。派生類構(gòu)造函數(shù)同樣是通過(guò)構(gòu)造函數(shù)初始化列表來(lái)將實(shí)參傳遞給基類構(gòu)造函數(shù)的。
每個(gè)類負(fù)責(zé)定義各自的接口。要想與類的對(duì)象交互必須使用類的接口,即使這個(gè)對(duì)象是派生類的基類部分也如此。盡管從語(yǔ)法上我們可以在派生類構(gòu)造函數(shù)體內(nèi)給它的 公有成員或受保護(hù)的基類成員賦值,但不建議這么做。
如果基類定義了一個(gè)靜態(tài)成員,則在整個(gè)繼承體系中只存在該成員的唯一定義。如果基類中的成員是private的,則派生類無(wú)權(quán)訪問(wèn)它。如果某靜態(tài)成員是可訪問(wèn)的,則我們既能通過(guò)基類使用它也能通過(guò)派生類使用它。
派生類的聲明:
class Bulk_Quote::public Quote;//錯(cuò)誤,不需要派生列表class Bulk_ Quote;//正確如果我們想將某個(gè)類作為基類,則該類必須是已經(jīng)定義而非僅聲明。
class Quote;//聲明未定義class Bulk_Quote:public Quote{};//錯(cuò)誤防止繼承的發(fā)生: C++11標(biāo)準(zhǔn)提供了一種防止繼承發(fā)生的方法,即在類名后跟一個(gè)關(guān)鍵字final.
靜態(tài)類型與動(dòng)態(tài)類型: 表達(dá)式的靜態(tài)類型在編譯時(shí)總是已知的,它是變量聲明時(shí)的類型或表達(dá)式生成的類型。動(dòng)態(tài)類型則是變量或表達(dá)式表示的內(nèi)存的對(duì)象的類型。動(dòng)態(tài)類型直到運(yùn)行時(shí)才知道。基類的指針或引用的靜態(tài)類型可能與其動(dòng)態(tài)類型不一致,取決于傳遞的實(shí)參。
因?yàn)橐粋€(gè)基類的對(duì)象可能是派生類對(duì)象的一部分,也可能不是,所以不存在基類向派生類的自動(dòng)類型轉(zhuǎn)換。即使一個(gè)基類指針或引用綁定在一個(gè)派生類對(duì)象上,我們也不能執(zhí)行從基類向派生類的轉(zhuǎn)換。
當(dāng)我們用一個(gè)派生類對(duì)象為一個(gè)基類對(duì)象初始化或者賦值時(shí),只有該派生類對(duì)象的基類部分會(huì)被拷貝、移動(dòng)或賦值,它的派生類部分被忽略掉。
Bulk_Quote bulk;//派生類對(duì)象Quote item(bulk);//調(diào)用Quote::Quote(const Quote&)item=bulk;//調(diào)用Quote::Operator=(const Quote&)虛函數(shù): 當(dāng)我們使用基類引用或指針調(diào)用一個(gè)虛成員函數(shù)時(shí)會(huì)執(zhí)行動(dòng)態(tài)綁定。因?yàn)槲覀冎钡竭\(yùn)行時(shí)才能知道到底調(diào)用了哪個(gè)版本的虛函數(shù),所以所有虛函數(shù)必須有定義。
基類中的虛函數(shù)在派生類中隱含地也是一個(gè)虛函數(shù)。當(dāng)派生類覆蓋了某個(gè)虛函數(shù)時(shí),該函數(shù)在基類中的形參必須與派生類中的形參嚴(yán)格匹配。
override說(shuō)明符說(shuō)明派生類中的虛函數(shù),final說(shuō)明之后任何嘗試覆蓋該函數(shù)的操作都將引發(fā)錯(cuò)誤。
如果我們通過(guò)基類的引用或指針調(diào)用函數(shù),則使用基類中定義的默認(rèn)實(shí)參,即使實(shí)際運(yùn)行的是派生類的函數(shù)版本也是如此,即傳入派生類函數(shù)的是基類函數(shù)定義的默認(rèn)實(shí)參。如果虛函數(shù)使用默認(rèn)實(shí)參,則基類和派生類中定義的默認(rèn)實(shí)參最好一致。
#include <iostream>class A{public: A(int v):v(v){}//A構(gòu)造函數(shù) virtual void print(int x=100)//基類虛函數(shù)默認(rèn)實(shí)參 { std::cout<<x<<std::endl; }private: int v;};class B:public A//派生類 {public: B(int v):A(v){}//B構(gòu)造函數(shù) void print(int x=10) override//默認(rèn)實(shí)參與基類不一致 { std::cout<<x+100<<std::endl;//傳入基類虛函數(shù)的默認(rèn)實(shí)參 }private: };int main(){ B b(10); A &aptr=b; aptr.print();//200 return 0;}如果我們希望對(duì)虛函數(shù)的調(diào)用不要進(jìn)行動(dòng)態(tài)綁定,而是強(qiáng)迫其執(zhí)行虛函數(shù)的某個(gè)特定版本,可以使用作用域運(yùn)算符。
//強(qiáng)行調(diào)用基類中定義的函數(shù)版本。double undiscounted=baseP->Quote::net_price(42);如果一個(gè)派生類虛函數(shù)需要調(diào)用它的基類版本,但是沒(méi)有使用作用域運(yùn)算符,則在運(yùn)行時(shí)該調(diào)用將被解析為對(duì)派生類版本自身的調(diào)用,從而導(dǎo)致無(wú)限遞歸。
抽象基類:
我們可以在函數(shù)體的位置書(shū)寫(xiě)=0來(lái)說(shuō)明一個(gè)虛函數(shù)為純虛函數(shù)。=0只能出現(xiàn)在類內(nèi)部的虛函數(shù)聲明語(yǔ)句處。我們可以為純虛函數(shù)提供定義,不過(guò)函數(shù)體必須定義在類外。
double net_price(std::size_t)const=0;//純虛函數(shù)含有(未經(jīng)覆蓋直接繼承)純虛函數(shù)的類是抽象基類。抽象基類負(fù)責(zé)定義接口,而后續(xù)的其他類可以覆蓋該接口。我們不能直接創(chuàng)建一個(gè)抽象基類的對(duì)象。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注