版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
第七章繼承性和派生類7.1基類和派生類
7.2單繼承
7.3多繼承
7.4虛基類
編輯課件7.1基類和派生類繼承(inheritance)機制是面向?qū)ο蟪绦蛟O計使代碼可以復用的最重要的手段,它允許程序員在保持原有類特性的基礎上進行擴展,增加功能。這樣產(chǎn)生新的類,稱派生類。派生類不是簡單地繼承基礎類的特性,它可以調(diào)整部分成員的特性,也可以增加一些新成員。繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O計的層次結構。體現(xiàn)了由簡單到復雜的認識過程。多態(tài)性(polymorphism)也是面向?qū)ο蟪绦蛟O計的標志性特征。多態(tài)性是考慮在不同層次的類中,以及在同一類中,同名的成員函數(shù)之間的關系問題。函數(shù)的重載,運算符的重載,屬于多態(tài)性中的編譯時的多態(tài)性。本章講解的以虛基類為基礎的多態(tài)性是運行時的多態(tài)性。體現(xiàn)了類推和比喻的思想方法。
編輯課件生物類動物類植物類微生物類脊椎動物類其它動物類哺乳動物類其它脊椎動物類靈長動物類其它動物類人類狒狒類其它靈長動物類編輯課件7.1基類和派生類1、基類與派生類基類(父類):已存在的用來派生新類的類;派生類(子類):由已存在的類派生出的新類;2、單繼承與多繼承單繼承:從一個基類派生的繼承;多繼承:從多個基類派生的繼承;編輯課件7.1基類和派生類基類1基類2……基類n派生類1派生類2基類派生類1派生類2(a)多重繼承
(b)單繼承
一個基類可以直接派生出多個派生類
派生出來的新類同樣可以作為基類再繼續(xù)派生出更新的類,依此類推形成一個層次結構。編輯課件7.1.1派生類的定義單繼承的定義格式為:class派生類名:繼承方式基類名 { 派生類新定義成員 };public:公有派生private:私有派生protected:保護派生規(guī)定基類成員在派生類中的訪問權限多繼承的定義格式為:class派生類名:繼承方式1基類名1,
繼承方式2基類名2,… { 派生類新定義成員};編輯課件單繼承的定義格式:classB//定義基類B{private: intx;protected: inty;public: intz; ...};classA:publicB
//由類B派生出類A{private: inta;protected: intb;public: intc; ...}Aa;//定義類A的一個對象a編輯課件7.1.1派生類的定義編制派生類時可分四步
吸收基類的成員
改造基類成員
發(fā)展新成員
重寫構造函數(shù)與析構函數(shù)
不論是數(shù)據(jù)成員,還是函數(shù)成員,除構造函數(shù)與析構函數(shù)外全盤接收
聲明一個和某基類成員同名的新成員派生類中的新成員就屏蔽了基類同名成員稱為同名覆蓋派生類新成員必須與基類成員不同名,它的加入保證派生類在功能上有所發(fā)展。編輯課件7.1.2派生類的三種繼承方式:公有繼承(public)保護繼承(private)私有繼承(protected)編輯課件公有繼承:公有繼承其特點是:
基類的公有成員和保護成員作為派生類的成員時,都保持原有狀態(tài),而私有成員仍是私有。編輯課件公有繼承:特別提示公有繼承時,派生類的對象只可訪問基類中的公有成員,不能訪問其它成員。派生類的成員函數(shù)可以訪問基類中的公有成員和保護成員,不可訪問其私有成員。編輯課件公有繼承:Public派生類對象基類對象Public編輯課件classB{private: intx;protected: inty;public: intz; ...};classA:publicB
{private: inta;protected: intb;public: intc; ...}Aa;說明:類B是基類,類A是從類B公有派生的,因此類B中的public、protected屬性的成員可繼承到類A中來,且保持原來的屬性。因此,類A中有5個數(shù)據(jù)成員:a,b,c,y(protected屬性),z(public屬性)。對象a可以直接訪問public成員z和c,不能訪問a,b,y。編輯課件注意:在不考慮派生類時,類中的private和protected屬性的成員沒有什么不同,它們都可以被類的成員函數(shù)訪問,而都不能被該類的對象直接訪問。其差異主要是在派生類中,當公有繼承時,基類中protected屬性的成員可以作為派生類的protected屬性的成員,而private屬性的成員不能作為派生類的成員編輯課件classstudent{private:intage;protected:charsex;public:intGetage();};classgraduatestudent:publicstudent{private:intstunum;public:intGetnum();};voidgraduatestudent::Getnum()//派生類成員函數(shù)定義{
//cout<<”age:”<<age<<endl;//不可訪問基類的私有成員cout<<”stunum:”<<stunum<<endl;//派生類的私有成員cout<<”age:”<<Getage()<<endl;//基類的公有成員cout<<“sex:”<<sex<<endl;
//即:student::sex
基類的保護成員}編輯課件保護繼承:其特點是:基類的所有公有成員和保護成員都作為派生類的保護成員,基類的私有成員仍是私有的。即基類的公有成員和保護成員都作為派生類的保護成員。派生類的其他成員可以直接訪問它們。派生類的對象不可以直接訪問它們。編輯課件.編輯課件classB{private: intx;protected: inty;public: intz; ...};classA:protectedB
{private: inta;protected: intb;public: intc; ...}Aa;說明:類B是基類,類A是從類B保護派生的,因此類B中的public、protected屬性的成員可繼承到類A中來,均變?yōu)閜rotected屬性。因此,類A中有5個數(shù)據(jù)成員:a,b,c,y(protected屬性),z(protected屬性)。對象a可以直接訪問public成員c,不能訪問a,b,y,z。編輯課件私有繼承:基類的公有成員和保護成員都作為派生類的私有成員,并且不能被這個派生類的子類所訪問。特別提示編輯課件.編輯課件classB{private: intx;protected: inty;public: intz; ...};classA:privateB
{private: inta;protected: intb;public: intc; ...}Aa;說明:類B是基類,類A是從類B私有派生的,因此類B中的public、protected屬性的成員可繼承到類A中來,均變?yōu)閜rivate屬性。因此,類A中有5個數(shù)據(jù)成員:a,b,c,y(private屬性),z(private屬性)。對象a可以直接訪問public成員c,不能訪問a,b,y,z。編輯課件公有派生和私有派生的訪問權限不可直接訪問不可直接訪問private不可直接訪問privateprotected不可直接訪問privatepublic私有派生
不可直接訪問不可直接訪問private不可直接訪問protectedprotected可直接訪問publicpublic公有派生
在派生類對象外訪問派生類對象的基類成員在派生類中對基類成員的訪問限定基類中的訪問限定
派生方式
編輯課件#include<iostream.h>classA{public:voidf1();protected:intj1;private:inti1;};classB:publicA{public:voidf2();protected:intj2;private:inti2;};classC:publicB{public:voidf3();};1、派生類B中成員函數(shù)f2()能否訪問基類A中的成員:f1()、j1和i1?2、派生類B的對象b1能否訪問基類A中的成員:f1()、j1和i1?3、派生類C中的成員函數(shù)f3()能否訪問直接基類B中的成員:f2()、j2和i2?能否訪問間接基類A中的成員:f1()、j1和i1?4、派生類C的對象c1能否訪問直接基類B中的成員:f2()、j2和i2?能否訪問間接基類A中的成員:f1()、j1和i1?編輯課件1、派生類B中成員函數(shù)f2()能否訪問基類A中的成員:f1()、j1和i1?
可以訪問f1()和j1,不可以訪問i1;原因:類B對類A是直接繼承,可以訪問A中的公有成員和保護成員,而不可以訪問私有成員;2、派生類B的對象b1能否訪問基類A中的成員:f1()、j1和i1?
可以訪問f1(),不可以訪問j1和i1;原因:類B的對象b1對類A中的成員是水平訪問,可以訪問A中的公有成員,而不可以訪問保護成員和私有成員;編輯課件4、派生類C的對象c1能否訪問直接基類B中的成員:f2()、j2和i2?能否訪問間接基類A中的成員:f1()、j1和i1?
可以訪問直接基類中的f2()和j2以及間接基類中的f1()和j1,不可以訪問i2和i1;
原因:類C對類B是直接繼承,原因同1;類C對類A是垂直訪問,可以訪問A中的公有成員和保護成員,而不可以訪問私有成員;可以訪問直接基類中的f2()以及間接基類中的f1(),其他都不可以訪問;
原因:類C的對象c1對B中的成員是水平訪問,原因同2;c1對A的訪問,相當于先直接繼承后水平訪問;3、派生類C中的成員函數(shù)f3()能否訪問直接基類B中的成員:f2()、j2和i2?能否訪問間接基類A中的成員:f1()、j1和i1?編輯課件#include<iostream.h>classA{public:voidf(inti){cout<<i<<endl;}voidg(){cout<<"g"<<endl;}};classB:A{public:voidh(){cout<<"h"<<endl;}A::f;};voidmain(){Bd1;d1.f(6);
d1.g();d1.h();}缺省繼承方式為private將基類中的成員說明為派生類中的成員編譯錯。B以私有繼承方式繼承A,因此B的對象b1不能訪問A的成員函數(shù)輸出(2):6h輸出(5):6gh編輯課件問題:1、執(zhí)行該程序時,哪個語句會出現(xiàn)編譯錯?2、去掉出錯語句后,執(zhí)行結果是什么?3、類B從類A繼承時的缺省繼承方式是什么?4、派生類B中,A::f的含義是什么?5、將B的繼承方式改為public,輸出結果是什么?編輯課件7.2單繼承在單繼承中,每個類可以生成多個派生類,但是每個派生類只能有一個基類。派生類中只有一個基類是單繼承的主要特點。編輯課件7.2.1派生類構造函數(shù)和析構函數(shù)1.派生類的構造函數(shù)構造函數(shù)不能被繼承;派生類構造函數(shù)的工作:對自己的數(shù)據(jù)成員進行初始化;負責調(diào)用基類構造函數(shù)使基類的數(shù)據(jù)成員得以初始化;調(diào)用子對象的構造函數(shù),對派生類中的子對象進行初始化;必須在成員初始化列表中進行編輯課件派生類構造函數(shù)格式:
<派生類名>(<派生類構造函數(shù)總參數(shù)表>)
:<基類構造函數(shù)>(<參數(shù)表1>),
<子對象名>(<參數(shù)表2>)
{<派生類中數(shù)據(jù)成員初始化>}成員初始化列表編輯課件成員初始化列表B(inti,intj,intk):a(i,j){b=k;}子對象a對子對象成員函數(shù)的調(diào)用輸出:6,78編輯課件#include<iostream.h>classA{public: A(inti); voidprint(); constint&r;//常引用類型private:
constinta;
//常類型
staticconstintb;
};
//靜態(tài)常類型constintA::b=10;
//常靜態(tài)成員的賦初值A::A(inti):a(i),r(a)
//對常數(shù)據(jù)成員的構造{}voidA::print(){cout<<a<<":"<<b<<":"<<r<<endl;}voidmain(){ Aa1(100),a2(0); a1.print(); a2.print();}A::A(inti){a=i,r=a;}//不能這樣喲!結果為:100:10:1000:10:0編輯課件派生類構造函數(shù)的調(diào)用順序如下:基類的構造函數(shù)子對象類的構造函數(shù)(若有)派生類構造函數(shù)編輯課件注意:1、若基類中未定義構造函數(shù),則派生類構造函數(shù)的定義中可以省略對基類構造函數(shù)的調(diào)用。2、若基類的構造函數(shù)使用了參數(shù),則派生類必須定義構造函數(shù),為基類構造函數(shù)提供參數(shù)。編輯課件#include<iostream.h>classA{public:A(){a=0;cout<<"A'sdefaultconstructorcalled.\n";}A(inti){a=i;cout<<"A'sconstructorcalled.\n";}~A(){cout<<"A'sdestructorcalled.\n";}voidprint()const{cout<<a<<",";}intGeta(){returna;}private:inta;};classB:publicA{public:B(){b=0;cout<<"B'sdefaultconstructorcalled.\n";}B(inti,intj,intk);~B(){cout<<"B'sdestructorcalled.\n";}voidprint();private:intb;Aaa;};B::B(inti,intj,intk):A(i),aa(j){b=k;cout<<"B'sconstructorcalled.\n";}voidB::print(){A::print();cout<<b<<","<<aa.Geta()<<endl;}voidmain(){Bbb[2];bb[0]=B(1,2,5);bb[1]=B(3,4,7);for(inti=0;i<2;i++) bb[i].print();}編輯課件#include<iostream.h>classdata{ intx;public: data(intx){data::x=x;cout<<"classdata\n";}};classA{public:A(intx):d1(x){cout<<"classA\n";}private: datad1;};classB:publicA{datad2;public:B(intx):A(x),d2(x){cout<<"classB\n";}};classC:publicB{public:C(intx):B(x) {cout<<"classC\n";}};voidmain(){Cobject(5);}classdataclassAclassdataclassBclassC編輯課件派生類析構函數(shù):執(zhí)行派生類的析構函數(shù)時,基類的析構函數(shù)也將被調(diào)用;析構函數(shù)不能被繼承;析構函數(shù)的執(zhí)行順序與構造函數(shù)嚴格相反;派生類的析構函數(shù);基類的析構函數(shù);編輯課件#include<iostream.h>classM{public:M(){m1=m2=0;};M(inti,intj);~M();voidPrint();private:intm1,m2;};M::M(inti,intj){m1=i,m2=j;cout<<"M'sconstructorcalled."<<m1<<","<<m2<<endl;}M::~M(){cout<<"M'sdestructorcalled."<<m1<<","<<m2<<endl;}voidM::Print(){cout<<m1<<","<<m2<<",";}classN:publicM{public:N(){n=0;}N(inti,intj,intk);~N();voidPrint();private:intn;};N::N(inti,intj,intk):M(i,j),n(k){cout<<"N'scostructorcalled."<<n<<endl;}N::~N(){cout<<"N'sdestructorcalled."<<n<<endl;}voidN::Print(){M::Print();cout<<n<<endl;}voidmain(){Nn1(5,6,7),n2(-2,-3,-4);n1.Print();n2.Print();}編輯課件運行結果:編輯課件3.派生類構造函數(shù)使用中應注意的問題派生類構造函數(shù)的定義中可以省略對基類構造函數(shù)的調(diào)用,其條件是在基類中必須有缺省的構造函數(shù)或者根本沒有定義任何構造函數(shù);當基類的構造函數(shù)使用一個或多個參數(shù)時,派生類必須定義構造函數(shù),提供將參數(shù)傳遞給基類構造函數(shù)的途徑;編譯器自動生成缺省構造函數(shù)設基類數(shù)據(jù)成員為m個,派生類數(shù)據(jù)成員為n個,派生類的參數(shù)個數(shù)為x,則:0=<x<=m+n;編輯課件#include<iostream.h>classA{public:A(){a=0;}A(inti){a=i;}voidPrint(){cout<<a<<",";}private:inta;};classB:publicA{public:B(){b1=b2=0;}B(inti){b1=i;b2=0;}B(inti,intj,intk):A(i),b1(j),b2(k){}voidPrint(){A::Print();cout<<b1<<","<<b2<<endl;}private:intb1,b2;};voidmain(){Bd1,d2(5),d3(4,5,6);d1.Print();d2.Print();d3.Print();}輸出:0,0,00,5,04,5,6編輯課件7.2.2子類型和賦值兼容規(guī)則1、子類型有一個特定的類型S,當且僅當它至少提供了類型T的行為,則稱類型S是類型T的子類型。子類型是類型間的一般和特殊的關系。在繼承中,公有繼承可以實現(xiàn)子類型。如:classA{public:voidprint()const{cout<<“ok!”;}};classB:publicA{public:voidf(){cout<<“No!”;}};voidf1(constA&r){r.print();}voidmain(){Bb;f1(b);}結果為:ok!對類A的對象操作的函數(shù),也就可對類A的子類(類B)的對象進行操作編輯課件2.類型適應指兩種類型之間的關系。如:派生類適應于基類。即派生類的對象可以用于基類對象所能使用的場合。子類型化與類型適應是一致的。子類型的重要性是能減輕編程負擔。一個函數(shù)可以用于某類型的對象,也就可用于該類型的各個子類型的對象,不必進行函數(shù)重載。編輯課件3.賦值兼容規(guī)則賦值兼容規(guī)則是指在需要基類對象的任何地方都可以使用公有派生類的對象來替代。在替代之后,派生類對象就可以作為基類的對象使用,但只能使用從基類繼承的成員。賦值兼容規(guī)則替代的幾種情況:派生類的對象可以賦值給基類對象。派生類的對象可以初始化基類的引用。派生類的對象的地址可以賦給指向基類的指針。編輯課件例題1下列對派生類的描述,()是錯的。A.一個派生類可以作另一個派生類的基類。B.派生類至少有一個基類。C.派生類的成員除了它自己的成員外,還包含了它的基類的成員。D.派生類中繼承的基類成員的訪問權限到派生類保持不變。答案:D編輯課件例題2派生類的對象對它基類成員中()是可以訪問的。A.公有繼承的公有成員;B.公有繼承的私有成員;C.公有繼承的保護成員;D.私有繼承的公有成員。答案:A編輯課件例題3對基類和派生類的關系描述中,()是錯誤。A.派生類是基類的具體化;B.派生類是基類的子集;C.派生類是基類定義的延續(xù);D.派生類是基類的組合。答案:B編輯課件例題4派生類的構造函數(shù)的成員初始化列表中,不能包含()。A.基類的構造函數(shù);B.派生類中子對象的初始化;C.基類的子對象的初始化;D.派生類中一般數(shù)據(jù)成員的初始化。答案:C編輯課件7.3多繼承在冊人員學生(單繼承)教職工(單繼承)兼職教師(單繼承)教師(單繼承)行政人員(單繼承)工人(單繼承)研究生(單繼承)行政人員兼教師(多重繼承)在職研究生(多重繼承)研究生助教(多重繼承)編輯課件7.3多繼承多繼承的定義格式為:class派生類名:繼承方式1基類名1,
繼承方式2基類名2,… { 派生類新定義成員};
由多個基類共同派生出新的派生類,這樣的繼承結構被稱為多重繼承或多繼承(multiple-inheritance)
編輯課件多重繼承的定義格式:如:classA{…};classB{…};classC:publicA,publicB{…};根據(jù)繼承的規(guī)定,派生類C的成員包含了基類A中成員和基類B中成員及該類本身的成員。編輯課件#include<iostream.h>classA{public: voidprintA(){cout<<"Hello";}};classB{public: voidprintB(){cout<<"C++";}};classC:publicA,publicB{public: voidprintC(){cout<<"World!\n";}};voidmain(){Cobj;; obj.printA(); obj.printB(); obj.printC();}HelloC++World!編輯課件7.3.2多繼承的構造函數(shù)和析構函數(shù)
<派生類名>(<總參數(shù)表>):<基類名1>(<參數(shù)表1>),<基類名2>(<參數(shù)表2>)……<子對象名>(<參數(shù)表n+1>),…...{<派生類構造函數(shù)體>}它必須同時負責該派生類所有基類構造函數(shù)的調(diào)用。同時,派生類的參數(shù)個數(shù)必須包含完成所有基類初始化所需的參數(shù)個數(shù)。編輯課件多繼承的構造函數(shù):派生類構造函數(shù)的調(diào)用順序是:先執(zhí)行所有基類的構造函數(shù)再執(zhí)行子對象類的構造函數(shù)(若有)再執(zhí)行派生類本身的構造函數(shù)注意:
同一層次的各基類構造函數(shù)的執(zhí)行順序取決于定義派生類時所指定的各基類順序,與派生類構造函數(shù)中所定義的成員初始化表的各項順序無關。編輯課件
定義基類B1
定義基類B2
定義基類B3派生類構造函數(shù)
定義派生類A
定義子對象bb
調(diào)用不同基類中的同名函數(shù)編輯課件運行結果:編輯課件多繼承的析構函數(shù):
在多繼承中,析構函數(shù)的執(zhí)行順序與構造函數(shù)的順序正好相反。編輯課件#include<iostream.h>classA{public: A(){cout<<"AConstructor"<<endl;} ~A(){cout<<"ADestructor"<<endl;}};classB{public: B(){cout<<"BConstructor"<<endl;} ~B(){cout<<"BDestructor"<<endl;}};classC:publicA,publicB{public: C(){cout<<"CConstructor"<<endl;} ~C(){cout<<"CDestructor"<<endl;}};voidmain(){Cc;}AConstructorBConstructorCConstructorCDestructorBDestructorADestructor編輯課件7.3.3多繼承的二義性問題1、產(chǎn)生二義性的原因在多繼承情況下,造成的對基類中某個成員的訪問出現(xiàn)的不唯一的情況;編輯課件二義性問題classAclassC:publicA,publicB{{public:public:
voidf();voidg();};voidh();classB};{public:
voidf();
voidg();};voidf();c1.f()A.f()B.f()C編輯課件二義性問題問題:若定義Cc1;,則c1.f()是否正確?答:c1.f()將產(chǎn)生二義性;原因:不能識別是調(diào)用類A或類B的f函數(shù);解決方法:
a.區(qū)別出是類A或類B的f函數(shù);
c1.A::f();
或c1.B::f();
b.在類中定義同名函數(shù)f;編輯課件二義性問題當一個派生類從多個基類派生,而這些基類又有一個共同的基類,則對該基類中說明的成員進行訪問時,可能會出現(xiàn)二義性;編輯課件二義性問題classAclassB2:publicA{{public:private:inta;intb2;};};classB1:publicAclassC:publicB1,publicB2{{private:public:intb1;intf();};private:intc;};c1.aA.aB1.b1CB2.b2A.a編輯課件二義性問題問題:若定義Cc1;,則c1.a與c1.A::a是否正確?答:c1.a與c1.A::a將產(chǎn)生二義性;原因:不能識別是通過類B1或類B2調(diào)用類A的a;解決方法:
a.區(qū)別出是通過類B1或類B2調(diào)用類A的a;
c1.B1::a;
或c1.B2::a;
b.虛基類;編輯課件2、二義性解決方法利用成員名限定法消除二義性;在類中定義一個同名成員;虛基類;編輯課件3、支配規(guī)則(定義同名成員方法)支配規(guī)則:類X中的名字N支配類Y中同名的名字N是指類X以類Y為它的一個基類;如果一個名字支配另外一個名字,則二者之間不存在二義性。當選擇該名字時,使用支配者的名字;編輯課件4、說明一個類不能從同一個類中直接繼承一次以上;二義性檢查在訪問控制和類型檢查之前進行,訪問控制和類型檢查不能解決二義性問題;編輯課件編輯課件運行結果:編輯課件7.4虛基類
引入目的:解決二義性問題;格式:virtual<繼承方式><基類名>說明:關鍵字virtual與關鍵字public或private的相對位置無關,但必須位于虛基類名之前,且virtual只對緊隨其后的基類名起作用;編輯課件7.4虛基類例如:classD:virtualpublicA,privateB,virutalpublicC其中:類A和類C是虛基類,而類B是非虛基類編輯課件classA{public:voidf();protected:inta;};classB:virtualpublicA{protected:intb;};classC:virtualpublicA{protected:intc;};classD:publicB,publicC{public:intg();private:intd;};虛基類虛基類BD.g()CA.f()下列各語句是否正確?Dn;n.f();voidD::g(){f();}正確能夠唯一確定調(diào)用類A的f();編輯課件7.4虛基類AAB1B2C非虛基類的類層次AB1B2C虛基類的類層次編輯課件虛基類的初始化由于派生類的對象中只有一個虛基類子對象。為保證虛基類子對象只被初始化一次,這個虛基類構造函數(shù)必須只被調(diào)用一次。編輯課件虛基類的初始化C++規(guī)定:虛基類子對象是由最派生類的構造函數(shù)通過調(diào)用虛基類的構造函數(shù)進行初始化的。虛基類的構造函數(shù)在非虛基類之前調(diào)用;若同一層次中包含多個虛基類,這些虛基類的構造函數(shù)按它們說明的次序調(diào)用;若虛基類由非虛基類派生而來,則仍先調(diào)用基類構造函數(shù),再調(diào)用派生類的構造函數(shù)。編輯課件最派生類:BDCAE若定義Ee;則E是最派生類;若定義Dd;則D是最派生類;若定義Bb;則B是最派生類;若定義Cc;則C是最派生類;編輯課件#include<iostream.h>classbase1{public:base1(){cout<<"classbase1"<<endl;}};classbase2{public:base2(){cout<<"classbase2"<<endl;}};classlevel1:publicbase2,virtualpublicbase1{public:level1(){cout<<"classlevel1"<<endl;}};classlevel2:publicbase2,virtualpublicbase1{public:level2(){cout<<"classlevel2"<<endl;}};classtoplevel:publiclevel1,virtualpubliclevel2{public:toplevel(){cout<<"classtoplevel1"<<endl;}};voidmain(){toplevelobj;}編輯課件運行結果:編輯課件說明:虛基類子對象由最派生類構造函數(shù)進行初始化;虛基類子對象只被初始化一次;虛基類構造函數(shù)先于非虛基類構造函數(shù)執(zhí)行;編輯課件基類子對象數(shù)據(jù)成員初始化虛基類非虛基類常數(shù)據(jù)成員靜態(tài)數(shù)據(jù)成員一般數(shù)據(jù)成員存在多個基類時,執(zhí)行順序取決于派生類定義時的順序存在多個子對象時,執(zhí)行順序取決于類中聲明的順序成員初始化列表類外初始化編輯課件設置虛基類的目的是:A簡化程序;B消除二義性;C提高運行效率D減少目標代碼答案:B編輯課件帶有虛基類的多層派生類構造函數(shù)的成員初始化列表中都要列出虛基類的構造函數(shù),這樣將對虛基類的子對象初始化()A與虛基類下面的派生類個數(shù)有關B多次C二次D一次答案:D編輯課件#include<iostream.h>classA{public:A(inti,intj){a=i;b=j;}voidMove(intx,inty){a+=x;b+=y;}voidShow(){cout<<"("<<a<<","<<b<<")"<<endl;}private:inta,b;};classB:publicA{public:B(inti,intj,intk,intl):A(i,j),x(k),y(l){}voidShow(){cout<<x<<","<<y<<endl;}voidfun(){Move(3,5);}voidf1(){A::Show();}private:intx,y;};voidmain(){Ae(1,2);e.Show();Bd(3,4,5,6);d.fun();d.A::Show();d.B::Show();d.f1();}編輯課件運行結果:編輯課件#include<iostream.h>classP{public:P(intp1,intp2){pri1=p1;pri2=p2;}intinc1(){return++pri1;}intinc2(){return++pri2;}voiddisplay(){cout<<"pri1="<<pri1<<",pri2="<<pri2<<endl;}private:intpri1,pri2;};classD1:virtualprivateP{public:D1(intp1,intp2,intp3):P(p1,p2){pri3=p3;}intinc1(){returnP::inc1();}intinc3(){return++pri3;}voiddisplay(){P::display();cout<<"pri3="<<pri3<<endl;}private:intpri3;};編輯課件classD2:virtualpublicP{public:D2(intp1,intp2,intp4):P(p1,p2){pri4=p4;}intinc1(){ P::inc1(); P::inc2(); returnP::inc1();}intinc4(){return++pri4;}voiddisplay(){P::display();cout<<"pri4="<<pri4<<endl;}private:intpri4;};編輯課件classD12:privateD1,publicD2{public:D12(intp11,intp12,intp13,intp21,intp22,intp23,intp):D1(p11,p12,p13),D2(p21,p22,p23),P(p11,p21){pri12=p;}intinc1(){D2::inc1();returnD2::inc1();}intinc5(){return++pri12;}voiddisplay(){cout<<"D2::display()\n";D2::display();cout<<"pri12="<<pri12<<endl;}private:intpri12;};編輯課件voidmain(){D12d(1,2,3,4,5,6,7);d.display();cout<<endl;d.inc4();d.inc5();d.D12::inc1();d.display();}編輯課件運行結果:編輯課件8.7多態(tài)性與虛函數(shù)C++的三大特征:封裝性繼承性多態(tài)性編輯課件
多態(tài)性是指同一個消息被不同類型的對象接收時產(chǎn)生不同的行為,特點就是一個接口,多個實現(xiàn)。C++中多態(tài)性按照類型可以分為強制多態(tài)、過載多態(tài)、包含多態(tài)和參數(shù)多態(tài)四種。8.7多態(tài)性與虛函數(shù)編輯課件8.7多態(tài)性與虛函數(shù)強制多態(tài)是指通過語義操作,強制數(shù)據(jù)做本不屬于該類型數(shù)據(jù)的操作。編譯器內(nèi)部的數(shù)據(jù)的隱式轉換,比如3.0+4操作時轉換成3.0+4.0就屬于此種類型重載多態(tài)是指函數(shù)重載,同名的操作在不同的環(huán)境下有不同的行為。前面學習過的普通函數(shù)重載和將要學習的類成員函數(shù)重載、運算符重載都屬于此種類型。包含多態(tài)是指在同一類族中定義于不同類中的同名函數(shù)的多態(tài)行為。我們本章將要學習的虛函數(shù)就屬于此種類型。參數(shù)多態(tài)是指功能、結構實現(xiàn)相同但所作用于的數(shù)據(jù)類型不同,也就是數(shù)據(jù)類型參數(shù)化的多態(tài)。函數(shù)模板和類模板就屬于此種多態(tài)。編輯課件多態(tài)的實現(xiàn):多態(tài)是指同一個消息被不同的對象接收產(chǎn)生不同的行為,因此,多態(tài)在實現(xiàn)的時候必須確定消息的操作對象。我們根據(jù)消息和對象相結合的時間分為兩種:在程序編譯連接階段完成的,也就是說在編譯的過程中確定了消息的操作對象,我們稱為靜態(tài)聯(lián)編(靜態(tài)束定)。在程序運行階段完成的,也就是說在程序運行的過程中才確定消息的操作對象,我們稱為動態(tài)聯(lián)編(動態(tài)束定)。編輯課件多態(tài)的實現(xiàn):多態(tài)性簡單多態(tài)性重要多態(tài)性虛函數(shù)函數(shù)重載、運算符重載
靜態(tài)聯(lián)編動態(tài)聯(lián)編編輯課件#include<iostream.h>classPoint{public: Point(doublei,doublej){x=i;y=j;} double
Area()const{return0.0;}private: doublex,y;};classRectangle:publicPoint{public: Rectangle(doublei,doublej,doublek,doublel); doubleArea()const{returnw*h;}private: doublew,h;};Rectangle::Rectangle(doublei,doublej,doublek,doublel):Point(i,j){ w=k;h=l;}voidfun(Point&s){ cout<<"Area="<<s.Area()<<endl;}voidmain(){
Rectanglerec(3.0,5.2,15.0,25.0); fun(rec);}Area=0編輯課件動態(tài)聯(lián)編:動態(tài)聯(lián)編:在程序執(zhí)行時進行的束定;實現(xiàn):C++動態(tài)束定在虛函數(shù)的支持下實現(xiàn);動態(tài)聯(lián)編的原因:當實現(xiàn)一個子類型時變動了其基類中相應行為的實現(xiàn)時,必須將這種變動告訴編譯器,即進行動態(tài)聯(lián)編;編輯課件8.7.1虛函數(shù)的定義1、虛函數(shù)虛函數(shù)是動態(tài)聯(lián)編的基礎;虛函數(shù)是非static成員函數(shù);virtual<類型說明符><函數(shù)名>(<參數(shù)表>)說明方法:編輯課件1、虛函數(shù)含義:若類中一成員函數(shù)被說明為虛函數(shù),則該成員函數(shù)在派生類中可能有不同的實現(xiàn)。當使用該成員函數(shù)操作指針或引用所標識的對象時,對該成員函數(shù)調(diào)用可采用動態(tài)聯(lián)編方式。操作方法:
動態(tài)聯(lián)編只能通過指針或引用標識對象來操作虛函數(shù)。如果采用一般類型的標識對象來操作虛函數(shù),則將采用靜態(tài)聯(lián)編方式調(diào)用虛函數(shù)。編輯課件#include<iostream.h>classPoint{public:Point(doublei,doublej){x=i;y=j;}
virtualdoubleArea()const{return0;}private:doublex,y;};classRectangle:publicPoint{public:Rectangle(inti,intj,intk,intl);
virtualdoubleArea()const{returnw*h;}private:doublew,h;};Rectangle::Rectangle(inti,intj,intk,intl):Point(i,j){w=k;h=l;}voidfun(Point&s){cout<<s.Area()<<endl;}voidmain(){Rectanglerect(3.0,5.2,15.0,25.0);fun(rect);}虛函數(shù)虛函數(shù)輸出:375編輯課件#include<iostream.h>classPoint{public:Point(doublei,doublej){x=i;y=j;}virtualdoubleArea()const{return0;}private:doublex,y;};classRectangle:publicPoint{public:Rectangle(inti,intj,intk,intl);virtualdoubleArea()const{returnw*h;}private:doublew,h;};Rectangle::Rectangle(inti,intj,intk,intl):Point(i,j){w=k;h=l;}voidfun(Point*s){cout<<s->Area()<<endl;}voidmain(){Rectanglerect(3.0,5.2,15.0,25.0);fun(&rect);}輸出:375編輯課件#include<iostream.h>classPoint{public:Point(doublei,doublej){x=i;y=j;}virtualdoubleArea()const{return0;}private:doublex,y;};classRectangle:publicPoint{public:Rectangle(inti,intj,intk,intl);virtualdoubleArea()const{returnw*h;}private:doublew,h;};Rectangle::Rectangle(inti,intj,intk,intl):Point(i,j){w=k;h=l;}voidfun(Points){cout<<s.Area()<<endl;}voidmain(){Rectanglerect(3.0,5.2,15.0,25.0);fun(rect);}輸出:0編輯
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024裝修增加項目施工合同模板
- 個人經(jīng)營貸款合同樣本
- 2024建筑單包工合同范文
- 2024股份擔保借款合同范本
- 2024個人住房公積金的借款合同
- 2024動產(chǎn)家具無償寄托合同
- 房產(chǎn)項目合作開發(fā)協(xié)議書
- 三輪車買賣合同完整協(xié)議2024年
- 倉配租賃合同模板
- 工業(yè)用地投資協(xié)議
- 2024中國一汽校園招聘1000+崗位高頻考題難、易錯點模擬試題(共500題)附帶答案詳解
- GB/T 19533-2024汽車用壓縮天然氣鋼瓶定期檢驗與評定
- 婦產(chǎn)科護士晉升述職報告
- 骨髓腔內(nèi)輸液(IOI)技術
- 建筑幕墻工程(鋁板、玻璃、石材)監(jiān)理實施細則(全面版)
- 小學數(shù)學與思政融合課教學設計
- 體育公園運營管理方案
- 休閑生態(tài)農(nóng)業(yè)觀光園建設項目財務分析及效益評價
- 江西省南昌市民德學校2023-2024學年八年級上學期期中數(shù)學試題
- 國際金融(英文版)智慧樹知到期末考試答案2024年
- 2024年《藥物臨床試驗質(zhì)量管理規(guī)范》(GCP)網(wǎng)絡培訓題庫
評論
0/150
提交評論