版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、PART III面 向 對 象 的 程 序 設(shè) 計引引 言言概 要 回 顧基于過程的程序設(shè)計基于對象的程序設(shè)計面向?qū)ο蟮某绦蛟O(shè)計 類的生成、設(shè)計類對象的使用C+過程化語言基礎(chǔ)問 題 的 回顧 俄羅斯方塊的設(shè)計與實現(xiàn) 基于過程的設(shè)計與實現(xiàn) 基于對象的設(shè)計與實現(xiàn) 方塊對象:七種方塊對象 圖框?qū)ο螅贺?fù)責(zé)繪制俄羅斯方塊運(yùn)行的圖框界面 判定對象:負(fù)責(zé)消行、統(tǒng)計分?jǐn)?shù)、方塊到頂游戲終結(jié)基 于 對 象 的 解 決 方 案 基 于 對 象 的 解 決 方 案 分 析 七種方塊: 公有屬性:顏色、速度、 不同屬性:形狀、 共同操作:右移、左移、下移、變形 各種操作由于形狀的不同而有不同的實現(xiàn) 這7種方塊的移動和變
2、形的實現(xiàn)方法不同,顯示也不同,因此不能用同一個類來描述 設(shè)計7個類分別描述7種方塊 7個方塊類中又有很多相同的,如顏色等數(shù)據(jù)屬性,都要四種移動操作,只是各自的實現(xiàn)方法有所不同問題1:共同的數(shù)據(jù)屬性在7個類中各自描述一次,顯得繁瑣,重復(fù),能夠簡化為統(tǒng)一描述?問題2:相同的操作能否在統(tǒng)一描述的同時方便地根據(jù)方塊類型調(diào)用不同的實現(xiàn)? 繼承和多態(tài)結(jié) 論 僅僅支持基于類的設(shè)計、生成和類對象的使用是不能稱為面向?qū)ο蟮某绦蛟O(shè)計 面向?qū)ο蟪绦蛟O(shè)計的四大主要特點 抽象 封裝 繼承 多態(tài)基于對象的程序設(shè)計面向?qū)ο蟮某绦蛟O(shè)計PARTIII 綱 要010102020303繼承與派生(重點)繼承與派生(重點)多態(tài)性與虛
3、函數(shù)(重點)多態(tài)性與虛函數(shù)(重點)輸入輸出流(常用)輸入輸出流(常用)0404C+ C+ 工具工具繼繼 承承 與與 派派 生生問 題 回 顧 與 分 析 共同的數(shù)據(jù)屬性在7個方塊類中各自描述一次,顯得繁瑣,重復(fù),能夠簡化為統(tǒng)一描述? 分析 先統(tǒng)一描述所有方塊的共性以及對全體方塊的處理功能;描述某一種方塊時,首先說明它是其中之一,然后再逐一描述這種方塊的個性 面向?qū)ο蟮某绦蛟O(shè)計中類的繼承與派生繼 承 與 派 生類類 的的 繼繼 承承派生類可以獲得基類的已有派生類可以獲得基類的已有特性特性派生類繼承了基類的所有數(shù)派生類繼承了基類的所有數(shù)據(jù)成員和成員函數(shù)據(jù)成員和成員函數(shù)類的繼承是層次結(jié)構(gòu)的類的繼承是
4、層次結(jié)構(gòu)的基類是派生類的抽象基類是派生類的抽象類的派生類的派生基類產(chǎn)生了一個和具有基類基類產(chǎn)生了一個和具有基類各種特性的新的子類各種特性的新的子類派生類可以對成員作必要的派生類可以對成員作必要的增加和調(diào)整增加和調(diào)整派生類又可以作為基類再派派生類又可以作為基類再派生出新的派生類生出新的派生類派生類是基類的具體化派生類是基類的具體化繼承派生在一個已經(jīng)存在的類(基類在一個已經(jīng)存在的類(基類/ /父類)的基礎(chǔ)之上父類)的基礎(chǔ)之上建立一個新的類(派生類建立一個新的類(派生類/ /子類)子類)繼 承 與 派 生 的 基 本 形 式單 繼 承 和 多 重 繼 承 單繼承 一個派生類只能由一個基類派生而來 一
5、個子類只有一個父類 多重繼承 一個派生類由多個(=2)基類派生而成 一個子類有兩個或者兩個以上的父類派 生 類 的 聲 明 一般形式class : ;派 生 類 實 例基類(普通學(xué)生類)基類(普通學(xué)生類)class student private: int ID; char *name; float score11; public: student(int n1,char*nm1) student()delete name; void print() . void get_name() ;派生類聲明(大學(xué)生類)派生類聲明(大學(xué)生類)class undergstudent : public :
6、public studentstudent private: char *major; /新增加的數(shù)據(jù)成員 float score40; public: void get_data print_major( ) /新增加的成員函數(shù) void print () 基類(普通學(xué)生類)基類(普通學(xué)生類)派生類聲明(大學(xué)生類)派生類聲明(大學(xué)生類)大學(xué)生類(未考慮訪問屬性)大學(xué)生類(未考慮訪問屬性) int ID; int ID; char char * *name;name; float score40;float score40; char char * *major;major; print_ma
7、jor( ) print_major( ) void print() .void print() . . .派 生 類 的 構(gòu) 成 兩大部分兩大部分 從基類繼承來的成員從基類繼承來的成員 聲明派生類時增加的部分聲明派生類時增加的部分 每一部分都分別包括數(shù)據(jù)成員和成員函數(shù)每一部分都分別包括數(shù)據(jù)成員和成員函數(shù) 構(gòu)成方式構(gòu)成方式 并非基類的成員和派生類增加成員的簡單加和并非基類的成員和派生類增加成員的簡單加和 接收基類的全部成員接收基類的全部成員 調(diào)整從基類接收的成員調(diào)整從基類接收的成員 聲明派生類時增加的成員聲明派生類時增加的成員 根據(jù)需要增加成員根據(jù)需要增加成員 定義派生類的構(gòu)造函數(shù)和定義派生類
8、的構(gòu)造函數(shù)和析構(gòu)析構(gòu)函數(shù)函數(shù)(不能從基類繼承而來)(不能從基類繼承而來)基 類 成 員 的 接 收 和 調(diào) 整 無條件地全部接收無條件地全部接收 不接收析構(gòu)函數(shù)和構(gòu)造函數(shù)不接收析構(gòu)函數(shù)和構(gòu)造函數(shù) 接收到的基類成員可以調(diào)整接收到的基類成員可以調(diào)整 通過指定繼承方式改變成員的訪問通過指定繼承方式改變成員的訪問屬性屬性 可以聲明同名成員加以覆蓋可以聲明同名成員加以覆蓋派 生 類 的 繼 承 方 式 三種繼承方式 public private protected 不同的繼承方式?jīng)Q定了基類成員在派生類中訪問屬性派 生 類 成 員 的 訪 問 屬 性 分情況處理 基類的成員函數(shù)訪問基類成員 派生類成員函數(shù)
9、訪問派生類自己增加的成員 基類的成員函數(shù)訪問派生類的成員 派生類外訪問派生類的成員 根據(jù)成員的訪問屬性判定能否由類外訪問該成員 派生類的成員函數(shù)訪問基類的成員 派生類外訪問基類的成員 核心問題:如何確定基類成員在派生類中的訪問屬性 基類成員聲明的訪問屬性 派生類對基類的繼承方式三 種 繼 承 方 式 下 派 生 類 中基 類 成 員 的 訪 問 控 制 權(quán) 限 繼承繼承 方式方式基類基類成員成員公有繼承公有繼承私有繼承私有繼承保護(hù)繼承保護(hù)繼承公有成員公有成員公有公有私有私有保護(hù)保護(hù)私有成員私有成員派生類成員不派生類成員不可訪問可訪問派生類成員不派生類成員不可訪問可訪問派生類成員不派生類成員不可
10、訪問可訪問保護(hù)成員保護(hù)成員保護(hù)保護(hù)私有私有保護(hù)保護(hù)公 有 繼 承基類的私有成員并沒有成為派生類的私有成員基類的私有成員僅僅只有基類的成員函數(shù)才能應(yīng)用基類的私有成員是派生類的不可訪問的成員基類的私有成員只能通過基類的公有成員函數(shù)加以訪問實例:基類student派生類undergstudent(公有繼承)假設(shè)一創(chuàng)建一個對象freshman是一個大一新生(Bob,10009,CS, )如何能夠正確獲取name、ID、major等信息?方 案 一 主函數(shù)調(diào)用freshman的公有成員函數(shù)get_data 派生類中g(shù)et_data如下定義:coutname;coutID;coutmajor;原因:nam
11、e和ID是基類的私有成員,在派生類中不可訪問方 案 二 基類中公有成員函數(shù)get_namecoutname; 基類中公有成員函數(shù)get_IDcoutID; 派生類中公有成員函數(shù)get_majorcoutmajor; 主函數(shù)中分別調(diào)用freshman的get_name、get_ID和get_major完成信息的獲取 公有繼承下,基類的公有成員在派生類中仍為公有,可在派生類外訪問方 案 三 主函數(shù)調(diào)用freshman的公有成員函數(shù)get_data 派生類中g(shù)et_data如下定義:get_name; /調(diào)用基類的成員函數(shù)get_ID;/調(diào)用基類的成員函數(shù)coutmajor; 基類中公有成員函數(shù)ge
12、t_name定義如下:coutname; 基類中公有成員函數(shù)get_ID定義如下:cout set_major(“EE”);/*不能訪問派生類增加的成員私 有 繼 承私有基類的公有成員和保護(hù)成員相當(dāng)于派生類中的私有成員派生類的成員可以訪問私有基類的公有成員和保護(hù)成員,但是派生類外不能訪問實例:情況與前述相同,唯一的區(qū)別是派生類undergstudent以私有繼承的方式由student類派生而成方 案 一 主函數(shù)調(diào)用freshman的公有成員函數(shù)get_data 派生類中g(shù)et_data如下定義:coutname;coutID;coutmajor;原因:name和ID是基類的私有成員,公有繼承下
13、在派生類中已不可訪問,私有繼承下依然不可行方 案 二 基類中公有成員函數(shù)get_namecoutname; 基類中公有成員函數(shù)get_IDcoutID; 派生類中公有成員函數(shù)get_majorcoutmajor; 主函數(shù)中分別調(diào)用freshman的get_name、get_ID和get_major完成信息的獲取 原因:私有繼承下,基類的公有成員等同于派生類的私有成員,無法在派生類外訪問方 案 三 主函數(shù)調(diào)用freshman的公有成員函數(shù)get_data 派生類中g(shù)et_data如下定義:get_name; /調(diào)用基類的成員函數(shù)get_ID;/調(diào)用基類的成員函數(shù)coutmajor; 基類中公有成
14、員函數(shù)get_name定義如下:coutname; 基類中公有成員函數(shù)get_ID定義如下:coutID;保 護(hù) 繼 承 保護(hù)成員 受保護(hù)的成員不能為類外訪問,但是可以被派生類的成員函數(shù)所引用基類(普通學(xué)生類)class student private: int ID; char *name; float score11; public: ;派生類聲明(大學(xué)生類)class undergstudent : public : public studentstudent private: char *major; /新增加的數(shù)據(jù)成員 float score40; public: class stu
15、dent protected: int ID; char *name; float score11; public: ;保 護(hù) 繼 承保護(hù)基類的公有成員和保護(hù)成員相當(dāng)于派生類中的保護(hù)成員派生類的成員可以訪問保護(hù)基類的公有成員和保護(hù)成員,但是派生類外不能訪問實例:情況與前述相同,但是派生類undergstudent以保護(hù)繼承的方式由student類派生而成第 一 種 情 形(ID 和name為私有數(shù)據(jù)) 基類(普通學(xué)生類)class student private:private: int ID; char *name; float score11; public: student(int n1
16、,char*nm1) student()delete name; void print() . void get_name() ;派生類聲明(大學(xué)生類)class undergstudent : protected : protected studentstudent private: char *major; /新增加的數(shù)據(jù)成員 float score40; public: void get_data print_major( ) /新增加的成員函數(shù) void print () 方 案 一 主函數(shù)調(diào)用freshman的公有成員函數(shù)get_data 派生類中g(shù)et_data如下定義:coutn
17、ame;coutID;coutmajor;原因:name和ID是基類的私有成員,保護(hù)繼承下在派生類中依然不可訪問方 案 二 基類中公有成員函數(shù)get_namecoutname; 基類中公有成員函數(shù)get_IDcoutID; 派生類中公有成員函數(shù)get_majorcoutmajor; 主函數(shù)中分別調(diào)用freshman的get_name、get_ID和get_major完成信息的獲取 原因:保護(hù)繼承下,基類的公有成員等同于派生類的保護(hù)成員,無法在派生類外訪問方 案 三 主函數(shù)調(diào)用freshman的公有成員函數(shù)get_data 派生類中g(shù)et_data如下定義:get_name; /調(diào)用基類的成員函
18、數(shù)get_ID;/調(diào)用基類的成員函數(shù)coutmajor; 基類中公有成員函數(shù)get_name定義如下:coutname; 基類中公有成員函數(shù)get_ID定義如下:coutID;第二種情形 (ID和name為保護(hù)成員數(shù)據(jù)) 基類(普通學(xué)生類)class student protected:protected: int ID; char *name; private: float score11; public: student(int n1,char*nm1) student()delete name; void print() . void get_name() ;派生類聲明(大學(xué)生類)cla
19、ss undergstudent : protected : protected studentstudent private: char *major; /新增加的數(shù)據(jù)成員 float score40; public: void get_data print_major( ) /新增加的成員函數(shù) void print () 方 案 一 主函數(shù)調(diào)用freshman的公有成員函數(shù)get_data 派生類中g(shù)et_data如下定義:coutname;coutID;coutmajor;原因:name和ID是基類的保護(hù)成員,公有繼承下和保護(hù)繼承下派生類中可以訪問方 案 二 基類中公有成員函數(shù)get_n
20、amecoutname; 基類中公有成員函數(shù)get_IDcoutID; 派生類中公有成員函數(shù)get_majorcoutmajor; 主函數(shù)中分別調(diào)用freshman的get_name、get_ID和get_major完成信息的獲取 原因:保護(hù)繼承下,基類的公有成員等同于派生類的保護(hù)成員,無法在派生類外訪問方 案 三 主函數(shù)調(diào)用freshman的公有成員函數(shù)get_data 派生類中g(shù)et_data如下定義:get_name; /調(diào)用基類的成員函數(shù)get_ID;/調(diào)用基類的成員函數(shù)coutmajor; 基類中公有成員函數(shù)get_name定義如下:coutname; 基類中公有成員函數(shù)get_ID
21、定義如下:coutID;保 護(hù) 成 員 和 保 護(hù) 繼 承 的 效 用 在類的在類的層次繼承結(jié)構(gòu)層次繼承結(jié)構(gòu)中找到數(shù)據(jù)中找到數(shù)據(jù)共享與成員隱蔽之間的最佳均衡共享與成員隱蔽之間的最佳均衡 如果需要在派生類中引用基類的如果需要在派生類中引用基類的某些成員,應(yīng)當(dāng)將基類中的這些某些成員,應(yīng)當(dāng)將基類中的這些成員聲明為成員聲明為protectedprotected,而非,而非privateprivate 以student類中的ID和name為例 如果聲明成為private,將造成派生類無法訪問的局面,使得派生類的使用很不方便 如果聲明成為public,使得基類的數(shù)據(jù)隱蔽性受到一定的損傷 如果聲明成為pro
22、tected,派生類可以訪問從而使得基類和派生類之間可以實現(xiàn)數(shù)據(jù)共享,基類和派生類的外部都不能訪問,保障了數(shù)據(jù)的隱蔽性多 級 派 生 下 的 訪 問 屬 性 類的層次繼承結(jié)構(gòu)導(dǎo)致了類的多級派生 基類 基類的派生類 派生類的派生類 直接派生類 vs. 間接派生類 直接基類 vs. 間接基類 多級派生情況下各成員的訪問屬性 在基類和其直接派生類之間按照一級派生訪問屬性的原則確定各成員的訪問屬性后逐級向下遷移派 生 類 的 構(gòu) 造 函 數(shù) 回顧:構(gòu)造函數(shù)的作用 對類中的數(shù)據(jù)成員進(jìn)行初始化 派生類的構(gòu)造函數(shù)的特殊性 派生類的數(shù)據(jù)成員構(gòu)成較為特殊 從基類中接收來的數(shù)據(jù)成員 派生類自己增加的數(shù)據(jù)成員 派生
23、類并沒有繼承基類的構(gòu)造函數(shù) 派生類的構(gòu)造函數(shù)的初始化工作 基類數(shù)據(jù)成員的初始化工作 派生類增加的數(shù)據(jù)成員的初始化工作派 生 類 實 例基類(普通學(xué)生類)基類(普通學(xué)生類)class student private: int ID; char *name; float score11; public: student(int n1,char*nm1) student()delete name; void print() . void get_name() ;派生類聲明(大學(xué)生類)派生類聲明(大學(xué)生類)class undergstudent : public : public studentstu
24、dent private: char *major; /新增加的數(shù)據(jù)成員 float score40; public: void get_data print_major( ) /新增加的成員函數(shù) void print () 實 例:大學(xué)生類undergstudent的構(gòu)造函數(shù)方案一undergstudentundergstudent(int n, string stu_name, string (int n, string stu_name, string stu_major, float stu_major, float * * scoreList) scoreList) ID = n;
25、ID = n; name= stu_name; name= stu_name; major = stu_major; major = stu_major; score = scoreList; score = scoreList; 派生類無法訪問基類的私有成員數(shù)派生類無法訪問基類的私有成員數(shù)據(jù)據(jù)方案二undergstudentundergstudent(int n, string stu_name, string (int n, string stu_name, string stu_major, float stu_major, float * * scoreList) scoreList)
26、 student(n, stu_name); student(n, stu_name); / /調(diào)用基類構(gòu)造函數(shù)調(diào)用基類構(gòu)造函數(shù) major = stu_major; major = stu_major; score = scoreList; score = scoreList; 不能在派生類構(gòu)造函數(shù)體中顯式調(diào)不能在派生類構(gòu)造函數(shù)體中顯式調(diào)用構(gòu)造函數(shù)!雖然能通過編譯,但用構(gòu)造函數(shù)!雖然能通過編譯,但結(jié)果不對結(jié)果不對派 生 類 構(gòu) 造 函 數(shù) 的 解 決 之 道方案三undergstudentundergstudent(int n, string stu_name, string (int n,
27、 string stu_name, string stu_major, float stu_major, float * * scoreList) scoreList): student(n, stu_name);: student(n, stu_name);/調(diào)用基類構(gòu)造函數(shù)調(diào)用基類構(gòu)造函數(shù) / /* *派生類的函數(shù)體中只對派生類派生類的函數(shù)體中只對派生類新增的數(shù)據(jù)成員進(jìn)行初始化新增的數(shù)據(jù)成員進(jìn)行初始化* */ / major = stu_major; major = stu_major; score = scoreList; score = scoreList; 解決的辦法是通過成員初始化
28、表來完成基類數(shù)據(jù)成員的初始化,在成員初始化表中可以顯式調(diào)用基類構(gòu)造函數(shù)派生類的函數(shù)體完成新增數(shù)據(jù)成員的初始化派 生 類 構(gòu) 造 函 數(shù) 的 基 本 形 式() :();說明:1、如果派生類構(gòu)造函數(shù)在類的外面定義,類體中只需要寫這個函數(shù)的聲明:() ;2、總參數(shù)表中的參數(shù)包括了基類構(gòu)造函數(shù)所需的參數(shù)和派生類新增數(shù)據(jù)成員初始化所需的參數(shù) 生成一個類對象(10009,bob,CS,) undergstudent(n, stu_name, stu_major, scorelist):student(n, stu_name)構(gòu)造函數(shù)的成員初始化表有 子 對 象 的 派 生 類 的 構(gòu) 造 函 數(shù) 子對象
29、 類的數(shù)據(jù)成員本身就是一個類對象class undergstudent : public : public studentstudent private: char *major; float score40; Teacher* tutor; /子對象 public: class teacher private: int ID; char* name; char* title; public: 分析: 對象建立時需要對它的數(shù)據(jù)成員進(jìn)行初始化 派生類構(gòu)造函數(shù)對其數(shù)據(jù)成員進(jìn)行初始化的時候也需要對其中的子對象進(jìn)行初始化 在成員初始化表中顯式調(diào)用子對象的構(gòu)造函數(shù)undergstudent (int n
30、, string stu_name, string stu_major, float * scoreList, int T_n, string T_name, string T_title): student(n, stu_name), tutor (T_n, T_name, T_title)派 生 類 構(gòu) 造 函 數(shù) 的 一 般 形 式():(), ();派生類構(gòu)造函數(shù)的任務(wù)派生類構(gòu)造函數(shù)的任務(wù)初始化基類數(shù)據(jù)成員初始化基類數(shù)據(jù)成員初始化子對象數(shù)據(jù)成員初始化子對象數(shù)據(jù)成員初始化其它派生類數(shù)據(jù)成員初始化其它派生類數(shù)據(jù)成員派生類構(gòu)造函數(shù)執(zhí)行順序派生類構(gòu)造函數(shù)執(zhí)行順序調(diào)用基類構(gòu)造函數(shù)調(diào)用基類構(gòu)造函數(shù)
31、調(diào)用子對象構(gòu)造函數(shù)調(diào)用子對象構(gòu)造函數(shù)執(zhí)行派生類構(gòu)造函數(shù)體執(zhí)行派生類構(gòu)造函數(shù)體特 殊 形 式 的 派 生 類 構(gòu) 造 函 數(shù) 多層派生時,不需要在成員初始化表中理出其上每一層派生類的構(gòu)造函數(shù),只需要列出其直接基類的構(gòu)造函數(shù)即可 派生類新增成員無需任何初始化時,派生類構(gòu)造函數(shù)的函數(shù)體唯恐 如果基類沒有定義構(gòu)造函數(shù),或者定義了沒有參數(shù)的構(gòu)造函數(shù),派生類定義構(gòu)造函數(shù)可以不寫基類構(gòu)造函數(shù),派生類構(gòu)造函數(shù)調(diào)用時,系統(tǒng)會自動首先調(diào)用基類的默認(rèn)構(gòu)造函數(shù)派 生 類 的 析 構(gòu) 函 數(shù) 回顧:析構(gòu)函數(shù)的作用 在對象撤銷之前,進(jìn)行必要的清理工作 派生類的析構(gòu)函數(shù) 對派生類新增加的成員進(jìn)行清理 根據(jù)需要定義相應(yīng)的析構(gòu)
32、函數(shù) 如果有子對象,還需要對子對象進(jìn)行清理 調(diào)用子對象的析構(gòu)函數(shù)完成 需要對接收自基類的成員進(jìn)行清理 調(diào)用基類的析構(gòu)函數(shù)完成派生類析構(gòu)函數(shù)的任務(wù)派生類析構(gòu)函數(shù)的任務(wù)清理基類數(shù)據(jù)成員清理基類數(shù)據(jù)成員清理子對象數(shù)據(jù)成員清理子對象數(shù)據(jù)成員清理其它派生類數(shù)據(jù)成員清理其它派生類數(shù)據(jù)成員派生類析構(gòu)函數(shù)執(zhí)行順序派生類析構(gòu)函數(shù)執(zhí)行順序調(diào)用基類析構(gòu)函數(shù)調(diào)用基類析構(gòu)函數(shù)調(diào)用子對象析構(gòu)函數(shù)調(diào)用子對象析構(gòu)函數(shù)執(zhí)行派生類析構(gòu)函數(shù)部分執(zhí)行派生類析構(gòu)函數(shù)部分派 生 類 的 同 名 覆 蓋 覆蓋規(guī)則 基類的同名成員在派生類中被屏蔽,成為不可見的 定義在派生類對象模塊中通過對象名訪問同名的成員,訪問的是派生類的成員 實例:st
33、udent student_A;undergstudent student_B;student_A.print();/調(diào)用基類中的成員函數(shù)printstudent_B.print();/調(diào)用派生類中的成員函數(shù)printstudent_B.student:print();/指明作用域而調(diào)用基類成員數(shù)據(jù)成員的覆蓋只要命名相同即可成員函數(shù)的覆蓋不僅函數(shù)名要相同,函數(shù)的參數(shù)表包括參數(shù)個數(shù)和類型都要相同多 重 繼 承 一個類可以從一個或者多個基類派生而來。根據(jù)派生類繼承基類的個數(shù),將繼承分為單繼承和多繼承。 當(dāng)派生類有多個基類時稱為多繼承。單繼承可以看作是多繼承的一個特例,多繼承可以看作是多個單繼承的組
34、合,它們有很多相同特性。 實例教師類在職研究生類研究生類多 重 繼 承 派 生 類 的 定 義class : , , ;多 重 繼 承 派 生 類 的 構(gòu) 造 函 數(shù) 成員初始化表中需要包含多個基類構(gòu)造函數(shù) 一般形式():(), , () ;多 重 繼 承 的 二 義 性 問 題 情形一:兩個基類有同名成員class gstudent: protected: int ID; char* name; char* major; public: init(); class teacher protected: int ID; char* name; char* title; public: init
35、(); class onjobgstudent: public gstudent, public teacher public: void print(); cout IDendl; coutnameendl; main() onjobgstudent Teach_A; Teach_A.init(); /該調(diào)用哪個init()? Teach_A.print(); /print函數(shù)該輸出哪個ID? /研究生學(xué)號和教師工號并不同二義性解 決 方 案 一用作用域運(yùn)算符“:”進(jìn)行限定,顯式訪問基類成員。main()main() onjobgstudent Teach_A; onjobgstudent
36、Teach_A; Teach_A.Teacher.init();Teach_A.Teacher.init(); Teach_A.gstudent.init(); Teach_A.gstudent.init(); Teach_A.print(); Teach_A.print(); class onjobgstudent: class onjobgstudent: public gstudent, public gstudent, public teacher public teacher public: public: void print(); void print(); cout coutT
37、eacher.IDTeacher.IDendl;endl; cout coutTT endl; endl; cout coutgstudent.IDgstudent.IDendl;endl; cout coutmajormajorendl;endl; 派生類的成員派生類的成員函數(shù)訪問基類函數(shù)訪問基類成員,不必寫成員,不必寫對象名對象名情 形 二:兩個基類和派生類都有同名成員class gstudent:class gstudent: protected: protected: int ID; int ID; char char* * name; na
38、me; char char* * major; major; public: public: void init(); void init(); class teacherclass teacher protected: protected: int ID; int ID; char char* * name; name; charchar* * title; title; public public: : void init(); void init(); class onjobgstudent: class onjobgstudent: public gstudent, public gs
39、tudent, public teacher public teacher public: public: void init(); void init(); void print(); void print(); main()main() onjobgstudent Teach_A; onjobgstudent Teach_A; Teach_A.init();Teach_A.init(); / /調(diào)用哪個調(diào)用哪個initinit? /根據(jù)同名覆蓋原則根據(jù)同名覆蓋原則 / /調(diào)用調(diào)用onjobgstudentonjobgstudent的的initinit Teach_A.print();Tea
40、ch_A.print(); 無二義性 內(nèi)在問題分析 Teacher_A.init調(diào)用類onjobgstudent的init函數(shù)進(jìn)行初始化,而類onjobgstudent的init函數(shù)分別調(diào)用了gstudent的init函數(shù)和teacher的init函數(shù)進(jìn)行基類數(shù)據(jù)成員的初始化 Teacher_A這個對象中保留了多份同名成員 teacher.ID gstudent.ID teacher.ID 和gstudent.ID互不相同必須保留 和相同保留多份同名數(shù)據(jù)占用空間,易出錯解 決 方 案 二:虛
41、基 類 的 引 入 派生類:在職研究生類 直接基類:教師類、研究生類 直接基類來自于同一個基類 (共同基類):Person類 教師類和研究生類 具有數(shù)據(jù)成員ID,不再具有name person類具有數(shù)據(jù)成員name情況是否有改善?教師類繼承person類的name研究生類繼承person類的name在職研究生類中仍有兩個同名name數(shù)據(jù)備份教師類在職研究生類研究生類Person類publicpublicpublicpublic虛 基 類 的 作 用 和 聲 明將Person類聲明為虛基類 使在職研究生類在多重繼承來自共同基類的直接基類時只保留一份同名成員 在職研究生類中只有一份name數(shù)據(jù),來
42、自于間接基類Person類虛基類的聲明教師類在職研究生類研究生類Person類virtual publicvirtual publicpublicpublicclass person /正常申明class teacher :virtual public persoclass gstudent :virtual public personclass onjobgstudent : public teacher, public gstudent注 意 事 項 虛基類在聲明派生類時,通過制定繼承方式虛基類在聲明派生類時,通過制定繼承方式時聲明時聲明class 派生類名派生類名 : virtual 繼
43、承方式繼承方式 虛基類名虛基類名 虛基類需要在其虛基類需要在其所有所有直接派生類中聲明為虛直接派生類中聲明為虛基類基類person類為虛基類,其直接派生類類為虛基類,其直接派生類teacher和和gstudent均需聲明均需聲明person為虛基類,缺一為虛基類,缺一不可不可課 后 思 考 題1 1、目前情況下,類、目前情況下,類teacherteacher和類和類gstudentgstudent仍然有同名數(shù)據(jù)成員:仍然有同名數(shù)據(jù)成員:IDID,請問類請問類onjobgstuentonjobgstuent如何處理該同如何處理該同名數(shù)據(jù)成員?名數(shù)據(jù)成員?2 2、如果、如果personperson
44、類中也增加一個數(shù)據(jù)類中也增加一個數(shù)據(jù)成員為成員為IDID用于存儲每個人的身份證號,用于存儲每個人的身份證號,又會出現(xiàn)什么情況?又會出現(xiàn)什么情況?虛 基 類 的 初 始 化引入虛基類之前的情況 在職研究生類的構(gòu)造函數(shù)進(jìn)行初始化時,調(diào)用教師類和研究生類各自的構(gòu)造函數(shù)進(jìn)行初始化,而教師類和研究生類各自的構(gòu)造函數(shù)又分別去調(diào)用person類的構(gòu)造函數(shù) 在職研究生類的構(gòu)造函數(shù)中只需要寫出它的直接基類teacher和gstudent的構(gòu)造函數(shù)即可教師類在職研究生類研究生類Person類publicpublicpublicpublic引 入 虛 基 類 后,在職研究生類中只保留了一份同名數(shù)據(jù)name 同名數(shù)據(jù)
45、來自虛基類Person類這一份數(shù)據(jù)成員的初始化必須由派生類直接完成 如果沿用原來的方式,共同基類person的初始化由teacher和gstudent分別調(diào)用,而進(jìn)行了多次初始化 不合理教師類在職研究生類研究生類Person類virtual publicvirtual publicpublicpublic虛 基 類 初 始 化 的 規(guī) 定 最后的派生類不僅要負(fù)責(zé)對其直接基最后的派生類不僅要負(fù)責(zé)對其直接基類進(jìn)行初始化,還需要負(fù)責(zé)虛基類的類進(jìn)行初始化,還需要負(fù)責(zé)虛基類的初始化初始化onjobgstudent (int t_n, int s_n, string fullname, string T_
46、title, string S_major): person (fullname), gstudent (s_n, S_major, fullname), teacher(t_n,T_tile, fullname)虛 基 類 初 始 化 的 說 明 C+編譯系統(tǒng)只執(zhí)行最后派生類對虛基類的構(gòu)造函數(shù)的調(diào)用,而忽略虛基類的其它派生類對虛基類的構(gòu)造函數(shù)的調(diào)用,保證虛基類的數(shù)據(jù)成員不會被多次初始化 構(gòu)造函數(shù)的調(diào)用順序(1)先調(diào)用虛基類的構(gòu)造函數(shù),再調(diào)用非虛基類的構(gòu)造函數(shù)(2)若同一層次中包含多個虛基類,其調(diào)用順序為定義時的順序(3)若虛基類由非虛基類派生而來,則仍按先調(diào)用基類構(gòu)造函數(shù),再調(diào)用派生類構(gòu)造函
47、數(shù)的順序引 入 繼 承 后 的 解 決 方 案 (俄 羅 斯 方 塊)class Shape int color;/基類成員 void leftshift() ; ;class L-shape: public shape /方塊類派生了L型方塊類 /L型方塊類繼承了方塊類,自動擁有其成員 char L-box2; /定義L型方塊類的形狀屬性 void leftshift() ; ;不 足 之 處 基類的leftshift()等成員函數(shù)的函數(shù)體均為空,在實現(xiàn)部分仍要寫出函數(shù)體,顯得冗余,本無必要,但為了統(tǒng)一規(guī)范類簇的基本行為,又不得不如此 主控程序每次隨機(jī)生成7種方塊中的一種,然后響應(yīng)鍵盤控制完
48、成相應(yīng)的操作和顯示,由于7種方塊對象分屬于7種方塊派生類創(chuàng)建,盡管主控程序中方塊對象的行為和操作保持一致,仍然需要將相似的代碼重復(fù)7遍,以保證調(diào)用和方塊對象一致的派生類中的成員函數(shù)while (;) int i =random()%7; if i = 0 create a L-shape object; detect keyboard; operate L-shape object; display; rule-control; if i= 1 create a 1-shape object; detect keyboard; operate 1-shape object; display;
49、rule-control; . 程序不夠簡潔To be continuedTo be continued多態(tài)性和虛函多態(tài)性和虛函數(shù)數(shù)多多 態(tài)態(tài) 性性 和和 虛虛 函函 數(shù)數(shù)問 題 的 分 析 有一個類簇,一個基類派生了不同的派生類,這個類簇具有統(tǒng)一的基本行為function,但是不同的派生類實現(xiàn)function的方法不統(tǒng)一 不同的派生類創(chuàng)建了一組不同的對象,這一組對象,接收到相同的信息,都需要完成function行為,但是由于對象由不同的派生類所創(chuàng)建,不同派生類完成類似功能的方法不同,需要分別調(diào)用不同內(nèi)容的函數(shù)來完成 目前的解決機(jī)制 既然function是這個類簇的統(tǒng)一的基本行為,所以基類中定
50、義統(tǒng)一的成員函數(shù)funciton 不同的派生類定義各自同名的成員函數(shù)function,根據(jù)同名覆蓋原則屏蔽基類的成員函數(shù),不同派生類創(chuàng)建的對象調(diào)用各自對應(yīng)的成員函數(shù)實 例class student:class student: protected: protected: int ID; int ID; char char* * name; name; public: public: void init(); void init(); void print(); void print(); class bachelor : public studentclass bachelor : publi
51、c student protected: protected: char char* * major; major; float score40;float score40; public public: : void init(); void init(); void print(); void print(); class master: public student, class master: public student, protected: protected: char char* * major; major; teacher advisor;/ teacher adviso
52、r;/導(dǎo)師導(dǎo)師 float score20;float score20; public public: : void init(); void init(); void print(); void print(); class doctor: public student, class doctor: public student, protected: protected: char char* * major; major; teacher advisor5;/ teacher advisor5;/導(dǎo)師組導(dǎo)師組 float score10;float score10; public pub
53、lic: : void init(); void init(); void print(); void print(); 需要打印所有學(xué)生的學(xué)籍情況bachelor stu1;stu1.print();master stu2;stu2.print();doctor stu3stu3.print();主函數(shù)中建立了3個不同類的對象,進(jìn)行了類似的操作,重復(fù)寫了3遍類似的語句繁瑣,不夠簡潔 理想狀態(tài)student *stu3=&stu1,&stu2,&stu3; /聲明基類指針數(shù)組for(int i=0;iprint(); /*單一指令,希望根據(jù)對象的類型調(diào)用對應(yīng)派生類的特定
54、函數(shù)*/ 對象stu1,stu2,stu3來自于同一個基類student,而基類與派生類對象間遵循類型兼容規(guī)則事實上,由于stu0, stu1和stu2只能訪問基類成員,所以調(diào)用的都是student類中的print函數(shù)解 決 機(jī) 制 動態(tài)多態(tài) 相對于靜態(tài)多態(tài)而言:函數(shù)重載、運(yùn)算符重載 特點:程序編譯時知道調(diào)用哪個函數(shù)(編譯時的多態(tài)性) 編譯時不能確定調(diào)用那個函數(shù),只有在程序運(yùn)行是才能動態(tài)確定操作所針對的對象 理想狀態(tài)下,stui.print()調(diào)用哪個函數(shù)取決于運(yùn)行時i的值 運(yùn)行時的多態(tài)性 引入虛函數(shù)虛 函 數(shù) 虛函數(shù)是一類特殊的基類成員函數(shù) 在基類中聲明,類內(nèi)用virtual 聲明 在派生類
55、中可重新定義,但函數(shù)名、函數(shù)類型、函數(shù)參數(shù)個數(shù)和類型必須與基類的虛函數(shù)相同,根據(jù)派生類需要重新定義函數(shù)體 派生類中沒有重新定義時,派生類簡單繼承其直接基類的虛函數(shù) 虛函數(shù)是C+語言的多態(tài)性質(zhì)和動態(tài)綁定的關(guān)鍵虛 函 數(shù) 的 特 性 特點 一個成員函數(shù)被申明為虛函數(shù)后,同一類簇內(nèi)所有類內(nèi)不能再定義與該虛函數(shù)具有相同參數(shù)和函數(shù)返回值類型的同名非virtual函數(shù) 一個函數(shù)一旦被聲明為虛函數(shù),則無論聲明它的類被繼承了多少層,在每一層派生類中該函數(shù)都保持虛函數(shù)特性。因此,在派生類中重新定義該函數(shù)時,可以省略關(guān)鍵字virtual。但是,為了提高程序的可讀性,往往不省略 當(dāng)有虛函數(shù)聲明時,virtual關(guān)鍵
56、字只用在虛函數(shù)的聲明中,不能用在虛函數(shù)定義中虛 函 數(shù) 的 作 用 作用 可以通過基類指針或者引用來訪問基類和派生類中的同名函數(shù) 基類指針指向某一派生類對象(符合賦值兼容原則),調(diào)用指針指向的派生類對象中的函數(shù)而非基類或者其它派生類中的函數(shù)(虛函數(shù)的作用) 突破了原來急了指針僅僅只能指向派生類對象中的基類部分的限制實 例class student:class student: protected: protected: int ID; int ID; char char* * name; name; public: public: void init(); void init(); virtu
57、al virtual void print();void print(); student student * *stu3=&stu1,&stu2,&stu3; stu3=&stu1,&stu2,&stu3; / /聲明基類指針數(shù)組聲明基類指針數(shù)組for(int i=0;i3;i+)for(int i=0;iprint(); stui-print(); / /* *printprint已申明為虛函數(shù)已申明為虛函數(shù)* */ / /stu0 /stu0將調(diào)用將調(diào)用bachelorbachelor的的printprint /stu1 /stu1將調(diào)用將
58、調(diào)用mastermaster的的printprint /stu0 /stu0將調(diào)用將調(diào)用doctordoctor的的printprint 多 態(tài) 的 分 類 C+中多態(tài)的分類 重載多態(tài):函數(shù)重載和運(yùn)算符重載 強(qiáng)制多態(tài):強(qiáng)制類型轉(zhuǎn)換 包含多態(tài):虛函數(shù) 參數(shù)多態(tài):函數(shù)模板和類模板 多 態(tài) 的 編 譯 實 現(xiàn) 編譯系統(tǒng)要根據(jù)已有的信息,對于同名函數(shù)的調(diào)用做出判斷,確定調(diào)用搞得是哪個函數(shù) 關(guān)聯(lián)/binding/聯(lián)編/綁定 靜態(tài)多態(tài) 靜態(tài)關(guān)聯(lián)、早期關(guān)聯(lián) 動態(tài)多態(tài) 動態(tài)關(guān)聯(lián)、滯后關(guān)聯(lián) C+規(guī)定,動態(tài)關(guān)聯(lián)通過繼承和虛函數(shù)來實現(xiàn)虛 函 數(shù) 申 明 注 意 事 項 靜態(tài)成員函數(shù)不能聲明為虛函數(shù)。因為靜態(tài)成員函數(shù)
59、不屬于某一個對象,沒有多態(tài)性的特征 構(gòu)造函數(shù)不能是虛函數(shù) 內(nèi)聯(lián)成員函數(shù)不能聲明為虛函數(shù)。因為內(nèi)聯(lián)函數(shù)的執(zhí)行代碼是明確的,在編譯時已被替換,沒有多態(tài)性的特征 析構(gòu)函數(shù)可以是虛函數(shù),且往往被定義為虛函數(shù)。一般來說,若某類中有虛函數(shù),則其析構(gòu)函數(shù)也應(yīng)當(dāng)定義為虛函數(shù)虛 析 構(gòu) 函 數(shù)申明格式virtual ();必要性實例若析構(gòu)函數(shù)并非虛函數(shù) stu是一個指向基類的指針變量,指向new開辟的空間 new開辟的空間是按照派生類doctor開辟的,所以除了name、ID之外,還為major、advisor、score申請了空間 delete stu僅僅調(diào)用了基類student的析構(gòu)函數(shù),僅僅釋放name、
60、ID的空間,而沒有釋放major、advisor、score的空間student student * *stu = stu = new doctornew doctor; ; /聲明基類指針指向聲明基類指針指向doctordoctor類類stu-print(); stu-print(); / /* *printprint已申明為虛函數(shù)已申明為虛函數(shù)* */ / /stu /stu將調(diào)用將調(diào)用doctordoctor的的printprintdelet stu;delet stu;return 0;return 0;純 虛 函 數(shù) 實例分析 福州大學(xué)中的學(xué)生總共就3類(bachelor、master、doctor),它們的共有基類student實際上是不需要實例化為任何對象的,因此student其實無需為虛函數(shù)print定義具體的實現(xiàn) 盡管基類本
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 研究生實證論文課程設(shè)計
- 現(xiàn)代舞課程設(shè)計
- 波形轉(zhuǎn)換課程設(shè)計
- 益生菌發(fā)酵課程設(shè)計
- 沈陽課程設(shè)計
- 神態(tài)表情訓(xùn)練課程設(shè)計
- 暖通施工課程設(shè)計
- 消費心理與行為課程設(shè)計
- 溪洛渡電廠課程設(shè)計
- 港口專業(yè)有哪些課程設(shè)計
- 2024版短視頻IP打造與授權(quán)運(yùn)營合作協(xié)議3篇
- 小學(xué)生防詐騙安全教育內(nèi)容
- 人工智能技術(shù)賦能多模態(tài)大學(xué)英語閱讀教學(xué)模式的探究
- 2023-2024學(xué)年浙江省寧波市鄞州區(qū)多校統(tǒng)編版六年級上冊期末考試語文試卷
- 裝修逾期索賠合同范例
- 云南省昆明市盤龍區(qū)2023-2024學(xué)年三年級上學(xué)期語文期末試卷
- 2024年貴州省六盤水市公開招聘警務(wù)輔助人員(輔警)筆試經(jīng)典練習(xí)卷(B)含答案
- 2024年醫(yī)院女工委工作計劃(6篇)
- 期末測試卷-2024-2025學(xué)年外研版(一起)英語六年級上冊(含答案含聽力原文無音頻)
- 人教版2025九年級道德與法治中考備考復(fù)習(xí)計劃
- 2024年度技術(shù)咨詢合同:某科技公司與某政府機(jī)構(gòu)關(guān)于技術(shù)咨詢服務(wù)的協(xié)議(2024版)2篇
評論
0/150
提交評論