轉(zhuǎn)載自https://github.com/applenob/Cpp_Primer_Practice,看C++primer的時(shí)用的筆記。自己做了一些補(bǔ)充,感謝前人的總結(jié)
成都創(chuàng)新互聯(lián)公司于2013年開始,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元宣州做網(wǎng)站,已為上家服務(wù),為宣州各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:13518219792
OOP:概述
- 面向?qū)ο蟪绦蛟O(shè)計(jì)(object-oriented programming)的核心思想是數(shù)據(jù)抽象、繼承和動(dòng)態(tài)綁定。
- 繼承(inheritance):
- 通過(guò)繼承聯(lián)系在一起的類構(gòu)成一種層次關(guān)系。
- 通常在層次關(guān)系的根部有一個(gè)基類(base class)。
- 其他類直接或者簡(jiǎn)介從基類繼承而來(lái),這些繼承得到的類成為派生類(derived class)。
- 基類負(fù)責(zé)定義在層次關(guān)系中所有類共同擁有的成員,而每個(gè)派生類定義各自特有的成員。
- 對(duì)于某些函數(shù),基類希望它的派生類個(gè)自定義適合自己的版本,此時(shí)基類就將這些函數(shù)聲明成虛函數(shù)(virtual function)。
- 派生類必須通過(guò)使用類派生列表(class derivation list)明確指出它是從哪個(gè)基類繼承而來(lái)。形式:一個(gè)冒號(hào),后面緊跟以逗號(hào)分隔的基類列表,每個(gè)基類前都可以有訪問(wèn)說(shuō)明符。
class Bulk_quote : public Quote{};
- 派生類必須在其內(nèi)部對(duì)所有重新定義的虛函數(shù)進(jìn)行聲明??梢栽诤瘮?shù)之前加上
virtual
關(guān)鍵字,也可以不加。C++11新標(biāo)準(zhǔn)允許派生類顯式地注明它將使用哪個(gè)成員函數(shù)改寫基類的虛函數(shù),即在函數(shù)的形參列表之后加一個(gè)override
關(guān)鍵字。
- 動(dòng)態(tài)綁定(dynamic binding,又稱運(yùn)行時(shí)綁定):
- 使用同一段代碼可以分別處理基類和派生類的對(duì)象。
- 函數(shù)的運(yùn)行版本由實(shí)參決定,即在運(yùn)行時(shí)選擇函數(shù)的版本。
定義基類和派生類
定義基類
- 基類通常都應(yīng)該定義一個(gè)虛析構(gòu)函數(shù),即使該函數(shù)不執(zhí)行任何實(shí)際操作也是如此。
- 基類通過(guò)在其成員函數(shù)的聲明語(yǔ)句前加上關(guān)鍵字
virtual
使得該函數(shù)執(zhí)行動(dòng)態(tài)綁定。
- 如果成員函數(shù)沒有被聲明為虛函數(shù),則解析過(guò)程發(fā)生在編譯時(shí)而非運(yùn)行時(shí)。
- 訪問(wèn)控制:
protected
: 基類和和其派生類還有友元可以訪問(wèn)。
private
: 只有基類本身和友元可以訪問(wèn)。
定義派生類
- 派生類必須通過(guò)類派生列表(class derivation list)明確指出它是從哪個(gè)基類繼承而來(lái)。形式:冒號(hào),后面緊跟以逗號(hào)分隔的基類列表,每個(gè)基類前面可以有一下三種訪問(wèn)說(shuō)明符的一個(gè):
public
、protected
、private
。
- C++11新標(biāo)準(zhǔn)允許派生類顯式地注明它將使用哪個(gè)成員函數(shù)改寫基類的虛函數(shù),即在函數(shù)的形參列表之后加一個(gè)
override
關(guān)鍵字。
- 派生類構(gòu)造函數(shù):派生類必須使用基類的構(gòu)造函數(shù)去初始化它的基類部分。
- 靜態(tài)成員:如果基類定義了一個(gè)基類成員,則在整個(gè)繼承體系中只存在該成員的唯一定義。
- 派生類的聲明:聲明中不包含它的派生列表。
- C++11新標(biāo)準(zhǔn)提供了一種防止繼承的方法,在類名后面跟一個(gè)關(guān)鍵字
final
。
類型轉(zhuǎn)換與繼承
- 理解基類和派生類之間的類型抓換是理解C++語(yǔ)言面向?qū)ο缶幊痰年P(guān)鍵所在。
- 可以將基類的指針或引用綁定到派生類對(duì)象上。
靜態(tài)類型與動(dòng)態(tài)類型:如果基類在實(shí)參中是引用或者指針的形式,那么就可以動(dòng)態(tài)類型轉(zhuǎn)換,即基類可以被派生類表示。但如果是實(shí)參既不是引用也不是指針,則它的靜態(tài)類型和動(dòng)態(tài)類型是一致的
- 不存在從基類向派生類的隱式類型轉(zhuǎn)換。
- 派生類向基類的自動(dòng)類型轉(zhuǎn)換只對(duì)指針或引用類型有效,對(duì)象之間不存在類型轉(zhuǎn)換。
- 如果將一個(gè)派生類對(duì)象賦值或拷貝給基類對(duì)象,該操作只會(huì)運(yùn)行基類成員的拷貝構(gòu)造函數(shù)或者賦值函數(shù),而派生類中的數(shù)據(jù)會(huì)被切掉(sliced down)/當(dāng)用一個(gè)派生類對(duì)象為一個(gè)基類對(duì)象初始化或賦值時(shí),只有該派生類對(duì)象中的基類部分會(huì)被拷貝、移動(dòng)或者賦值,它的派生類部分將會(huì)被忽略掉
存在繼承關(guān)系的類型之間的轉(zhuǎn)換規(guī)則
- 從派生類向基類的類型轉(zhuǎn)換只對(duì)指針或引用類型有效
- 基類向派生類不存在隱式類型轉(zhuǎn)換
- 和任何其他成員一樣,派生類想基類的類型轉(zhuǎn)換也可能會(huì)由于訪問(wèn)受限而變得不可行
虛函數(shù)
-
使用虛函數(shù)可以執(zhí)行動(dòng)態(tài)綁定。
-
OOP的核心思想是多態(tài)性(polymorphism)。
- 引用或指針的靜態(tài)類型和動(dòng)態(tài)類型不同這一事實(shí)正是c++支持多態(tài)的根本所在
-
當(dāng)且僅當(dāng)對(duì)通過(guò)指針或引用調(diào)用虛函數(shù)時(shí),才會(huì)在運(yùn)行時(shí)解析該調(diào)用,也只有在這種情況下對(duì)象的動(dòng)態(tài)類型才有可能與靜態(tài)類型不同。
-
派生類必須在其內(nèi)部對(duì)所有重新定義的虛函數(shù)進(jìn)行聲明??梢栽诤瘮?shù)之前加上virtual
關(guān)鍵字,也可以不加。
-
C++11新標(biāo)準(zhǔn)允許派生類顯式地注明它將使用哪個(gè)成員函數(shù)改寫基類的虛函數(shù),即在函數(shù)的形參列表之后加一個(gè)override
關(guān)鍵字。
-
如果我們想覆蓋某個(gè)虛函數(shù),但不小心把形參列表弄錯(cuò)了,這個(gè)時(shí)候就不會(huì)覆蓋基類中的虛函數(shù)。加上override
可以明確程序員的意圖,讓編譯器幫忙確認(rèn)參數(shù)列表是否出錯(cuò)。
-
如果虛函數(shù)使用默認(rèn)實(shí)參,則基類和派生類中定義的默認(rèn)實(shí)參最好一致。
-
通常,只有成員函數(shù)(或友元)中的代碼才需要使用作用域運(yùn)算符(::
)來(lái)回避虛函數(shù)的機(jī)制。
抽象基類
- 純虛函數(shù)(pure virtual):清晰地告訴用戶當(dāng)前的函數(shù)是沒有實(shí)際意義的。純虛函數(shù)無(wú)需定義,只用在函數(shù)體的位置前書寫
=0
就可以將一個(gè)虛函數(shù)說(shuō)明為純虛函數(shù)。
- 含有純虛函數(shù)的類是抽象基類(abstract base class)。不能創(chuàng)建抽象基類的對(duì)象。
- 派生類構(gòu)造函數(shù)只初始化他的直接基類,也就是說(shuō)派生類如果沒有自己的數(shù)據(jù)成員也要提供一個(gè)接受基類中參數(shù)的構(gòu)造函數(shù)。
訪問(wèn)控制與繼承
- 受保護(hù)的成員:
protected
說(shuō)明符可以看做是public
和private
中的產(chǎn)物。
- 類似于私有成員,受保護(hù)的成員對(duì)類的用戶來(lái)說(shuō)是不可訪問(wèn)的。
- 類似于公有成員,受保護(hù)的成員對(duì)于派生類的成員和友元來(lái)說(shuō)是可訪問(wèn)的。
- 派生類的成員或友元只能通過(guò)派生類對(duì)象來(lái)訪問(wèn)基類的受保護(hù)成員。派生類對(duì)于一個(gè)基類對(duì)象中的受保護(hù)成員沒有任何訪問(wèn)特權(quán)。
- 派生訪問(wèn)說(shuō)明符:
- 對(duì)于派生類的成員(及友元)能否訪問(wèn)其直接基類的成員沒什么影響。
- 派生訪問(wèn)說(shuō)明符的目的是:控制派生類用戶對(duì)于基類成員的訪問(wèn)權(quán)限(即類的使用者的權(quán)限,如果是private,則不能通過(guò)派生類直接調(diào)用基類中的數(shù)據(jù)成員)。比如
struct Priv_Drev: private Base{}
意味著在派生類Priv_Drev
中,從Base
繼承而來(lái)的部分都是private
的。
- 友元關(guān)系不能繼承。
- 改變個(gè)別成員的可訪問(wèn)性:使用
using
。
- 默認(rèn)情況下,使用
class
關(guān)鍵字定義的派生類是私有繼承的;使用struct
關(guān)鍵字定義的派生類是公有繼承的。
- 15.18:派生類公有的繼承基類的時(shí)候,用戶代碼才能使用派生類向基類轉(zhuǎn)換
繼承中的類作用域
- 每個(gè)類定義自己的作用域,在這個(gè)作用域內(nèi)我們定義類的成員。當(dāng)存在繼承關(guān)系時(shí),派生類的作用域嵌套在其基類的作用域之內(nèi)。
- 派生類的成員將隱藏同名的基類成員。
- 除了覆蓋繼承而來(lái)的虛函數(shù)之外,派生類最好不要重用其他定義在基類中的名字。
名字查找與繼承
假設(shè)調(diào)用p->mem()或者obj.mem(),需要依次調(diào)用以下四個(gè)步驟:
- 首先確定p的靜態(tài)類型。因?yàn)槲覀冋{(diào)用的是一個(gè)成員,所以該類型必然是類類型。
- 在p的靜態(tài)類型對(duì)應(yīng)的類中查找mem。如果找不到,則依次在直接基類中不斷查找直至到達(dá)繼承鏈的頂端。如果找遍了該類及其基類仍然找不到,則編譯器將報(bào)錯(cuò)。
- 一旦找到了mem,就進(jìn)行常規(guī)的類型檢查已確認(rèn)對(duì)于當(dāng)前找到的mem,本次調(diào)用是否合法。
- 假設(shè)調(diào)用合法,則編譯器將根據(jù)調(diào)用的是否是虛函數(shù)而產(chǎn)生不同的代碼:
- 如果mem是虛函數(shù)且我們是通過(guò)引用或指針進(jìn)行的調(diào)用,則編譯器產(chǎn)生的代碼將在運(yùn)行時(shí)確定到底運(yùn)行該虛函數(shù)的哪個(gè)版本,依據(jù)是對(duì)象的動(dòng)態(tài)類型
- 反之,如果mem不是虛函數(shù)或者我們是通過(guò)對(duì)象(而非指針或引用)進(jìn)行的調(diào)用,則編譯器將產(chǎn)生一個(gè)常規(guī)函數(shù)調(diào)用。
構(gòu)造函數(shù)與拷貝控制
虛析構(gòu)函數(shù)
- 基類通常應(yīng)該定義一個(gè)虛析構(gòu)函數(shù),這樣我們就能動(dòng)態(tài)分配繼承體系中的對(duì)象了。
- 如果基類的析構(gòu)函數(shù)不是虛函數(shù),則
delete
一個(gè)指向派生類對(duì)象的基類指針將產(chǎn)生未定義的行為。
- 虛析構(gòu)函數(shù)將阻止合成移動(dòng)操作。
合成拷貝控制與繼承
- 基類或派生類的合成拷貝控制成員的行為和其他合成的構(gòu)造函數(shù)、賦值運(yùn)算符或析構(gòu)函數(shù)類似:他們對(duì)類本身的成員依次進(jìn)行初始化、賦值或銷毀的操作。
- 如果基類中的默認(rèn)構(gòu)造函數(shù),拷貝構(gòu)造函數(shù)、拷貝賦值函數(shù)或者析構(gòu)函數(shù)是被刪除的函數(shù)或者不可訪問(wèn),則派生類中對(duì)應(yīng)的成員將是被刪除的
- 如果在基類中有一個(gè)不可訪問(wèn)或者刪除掉的析構(gòu)函數(shù),則派生類中合成的默認(rèn)和拷貝構(gòu)造函數(shù)將是被刪除的,因?yàn)榫幾g器無(wú)法銷毀派生類對(duì)象的基類部分
- 如果派生類確實(shí)需要移動(dòng)操作,需要在基類中定義移動(dòng)操作。只要有移動(dòng)操作就必須有顯式的拷貝操作
派生類的拷貝控制成員
- 當(dāng)派生類定義了拷貝或移動(dòng)操作時(shí),該操作負(fù)責(zé)拷貝或移動(dòng)包括基類部分成員在內(nèi)的整個(gè)對(duì)象。
- 派生類析構(gòu)函數(shù):派生類析構(gòu)函數(shù)先執(zhí)行,然后執(zhí)行基類的析構(gòu)函數(shù)。
繼承的構(gòu)造函數(shù)
- C++11新標(biāo)準(zhǔn)中,派生類可以重用其直接基類定義的構(gòu)造函數(shù)。
- 如
using Disc_quote::Disc_quote;
,注明了要繼承Disc_quote
的構(gòu)造函數(shù)。
容器與繼承
- 當(dāng)我們使用容器存放繼承體系中的對(duì)象時(shí),通常必須采用間接存儲(chǔ)的方式。
- 派生類對(duì)象直接賦值給積累對(duì)象,其中的派生類部分會(huì)被切掉。
- 在容器中放置(智能)指針而非對(duì)象。
- 對(duì)于C++面向?qū)ο蟮木幊虂?lái)說(shuō),一個(gè)悖論是我們無(wú)法直接使用對(duì)象進(jìn)行面向?qū)ο缶幊?。相反,我們必須使用指針和引用。因?yàn)橹羔槙?huì)增加程序的復(fù)雜性,所以經(jīng)常定義一些輔助的類來(lái)處理這些復(fù)雜的情況。
文本查詢程序再探
- 使系統(tǒng)支持:?jiǎn)卧~查詢、邏輯非查詢、邏輯或查詢、邏輯與查詢。
面向?qū)ο蟮慕鉀Q方案
- 將幾種不同的查詢建模成相互獨(dú)立的類,這些類共享一個(gè)公共基類:
WordQuery
NotQuery
OrQuery
AndQuery
- 這些類包含兩個(gè)操作:
eval
:接受一個(gè)TextQuery
對(duì)象并返回一個(gè)QueryResult
。
rep
:返回基礎(chǔ)查詢的string
表示形式。
- 繼承和組合:
- 當(dāng)我們令一個(gè)類公有地繼承另一個(gè)類時(shí),派生類應(yīng)當(dāng)反映與基類的“是一種(Is A)”的關(guān)系。
- 類型之間另一種常見的關(guān)系是“有一個(gè)(Has A)”的關(guān)系。
- 對(duì)于面向?qū)ο缶幊痰男率謥?lái)說(shuō),想要理解一個(gè)程序,最困難的部分往往是理解程序的設(shè)計(jì)思路。一旦掌握了設(shè)計(jì)思路,接下來(lái)的實(shí)現(xiàn)也就水到渠成了。
Query程序設(shè)計(jì):
操作 |
解釋 |
Query 程序接口類和操作 |
|
TextQuery |
該類讀入給定的文件并構(gòu)建一個(gè)查找圖。包含一個(gè)query 操作,它接受一個(gè)string 實(shí)參,返回一個(gè)QueryResult 對(duì)象;該QueryResult 對(duì)象表示string 出現(xiàn)的行。 |
QueryResult |
該類保存一個(gè)query 操作的結(jié)果。 |
Query |
是一個(gè)接口類,指向Query_base 派生類的對(duì)象。 |
Query q(s) |
將Query 對(duì)象q 綁定到一個(gè)存放著string s 的新WordQuery 對(duì)象上。 |
q1 & q2 |
返回一個(gè)Query 對(duì)象,該Query 綁定到一個(gè)存放q1 和q2 的新AndQuery 對(duì)象上。 |
q1 | q2 |
返回一個(gè)Query 對(duì)象,該Query 綁定到一個(gè)存放q1 和q2 的新OrQuery 對(duì)象上。 |
~q |
返回一個(gè)Query 對(duì)象,該Query 綁定到一個(gè)存放q 的新NotQuery 對(duì)象上。 |
Query 程序?qū)崿F(xiàn)類 |
|
Query_base |
查詢類的抽象基類 |
WordQuery |
Query_base 的派生類,用于查找一個(gè)給定的單詞 |
NotQuery |
Query_base 的派生類,用于查找一個(gè)給定的單詞 |
BinaryQuery |
Query_base 的派生類,查詢結(jié)果是Query 運(yùn)算對(duì)象沒有出現(xiàn)的行的集合 |
OrQuery |
Query_base 的派生類,返回它的兩個(gè)運(yùn)算對(duì)象分別出現(xiàn)的行的并集 |
AndQuery |
Query_base 的派生類,返回它的兩個(gè)運(yùn)算對(duì)象分別出現(xiàn)的行的交集 |
網(wǎng)頁(yè)名稱:第十五章 面向?qū)ο蟪绦蛟O(shè)計(jì)
文章源于:
http://weahome.cn/article/dsoipig.html