清華大學(xué)C++課件-第五講 多態(tài)性_799209805_第1頁
清華大學(xué)C++課件-第五講 多態(tài)性_799209805_第2頁
清華大學(xué)C++課件-第五講 多態(tài)性_799209805_第3頁
清華大學(xué)C++課件-第五講 多態(tài)性_799209805_第4頁
清華大學(xué)C++課件-第五講 多態(tài)性_799209805_第5頁
已閱讀5頁,還剩77頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、第五講第五講 多態(tài)性多態(tài)性多態(tài)性多態(tài)性概述多態(tài)性概述運算符重載運算符重載虛函數(shù)與多態(tài)虛函數(shù)與多態(tài)虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)純虛函數(shù)與抽象類純虛函數(shù)與抽象類程序?qū)嵗绦驅(qū)嵗鄳B(tài)類型小結(jié)多態(tài)類型小結(jié)運行時類型識別運行時類型識別綜合實例綜合實例n多態(tài)是指操作接口具有表現(xiàn)多種形態(tài)的能力,即能根據(jù)操作環(huán)境的不同采用不同的處理方式。多態(tài)性是面向?qū)ο笙到y(tǒng)的主要特性之一,在這樣的系統(tǒng)中,一組具有相同基本語義的方法能在同一接口下為不同的對象服務(wù)。nC+語言支持的多態(tài)性可以按其實現(xiàn)的時機分為編譯時多態(tài)和運行時多態(tài)兩類。多態(tài)性概述n多態(tài)的類型n重載多態(tài):函數(shù)重載及運算符重載n強制多態(tài):隱式類型轉(zhuǎn)換及強制類型轉(zhuǎn)換n包含多態(tài)

2、:基類及子類中同名成員函數(shù)的多態(tài)行為n參數(shù)多態(tài):函數(shù)模板及類模板nC+不但提供了固有的多態(tài)性,還提供了實現(xiàn)自定義多態(tài)性的手段。多態(tài)性概述n多態(tài)的種類n編譯時的多態(tài)n運行時的多態(tài)n綁定是指把一個標識符名和一個存儲地址聯(lián)系在一起的過程n編譯時的多態(tài)n綁定工作在編譯連接階段完成的情況稱為靜態(tài)綁定n運行時的多態(tài)n綁定工作在程序運行階段完成的情況稱為動態(tài)綁定多態(tài)性概述多態(tài)性多態(tài)性概述多態(tài)性概述運算符重載運算符重載虛函數(shù)與多態(tài)虛函數(shù)與多態(tài)虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)純虛函數(shù)與抽象類純虛函數(shù)與抽象類程序?qū)嵗绦驅(qū)嵗鄳B(tài)類型小結(jié)多態(tài)類型小結(jié)運行時類型識別運行時類型識別綜合實例綜合實例n用“+”、“-”能夠?qū)崿F(xiàn)復(fù)數(shù)的加

3、減運算嗎?n實現(xiàn)復(fù)數(shù)加減運算的方法 重載“+”、“-”運算符n運算符重載是對已有的運算符賦予多重含義,使同一個運算符作用于不同類型的數(shù)據(jù)時導(dǎo)致不同的行為。運算符重載nC+ 幾乎可以重載全部的運算符,而且只能夠只能夠重載重載C+中已經(jīng)有的運算符中已經(jīng)有的運算符n重載之后運算符的優(yōu)先級和結(jié)合性都不會運算符改變n運算符重載是針對新類型數(shù)據(jù)的實際需要,對原有運算符進行適當?shù)母脑靚兩種重載方式:重載為類的非靜態(tài)成員函數(shù)和重載為非成員函數(shù)運算符重載運算符重載nC+中可以被重載的操作符:nC+中不能被重載的操作符: n“.”、“.*”、“:”、“? :”nC+要求,重載時,賦值”=“、下標”、調(diào)用”()”和

4、成員訪問箭頭”-”操作符必須被重載為類的成員函數(shù)n聲明形式函數(shù)類型 類名:operator 運算符 (形參) .n重載為類成員函數(shù)時 參數(shù)個數(shù)=原操作數(shù)個數(shù)-1 (后置+、-除外)n重載為非成員函數(shù)時 參數(shù)個數(shù)=原操作數(shù)個數(shù),且至少應(yīng)該有一個自定義類型的形參運算符重載運算符前后可以有空運算符前后可以有空格,也可以沒有空格格,也可以沒有空格n雙目運算符 Bn如果要重載 B 為類成員函數(shù),使之能夠?qū)崿F(xiàn)表達式 oprd1 B oprd2,其中 oprd1 為A 類對象,則 B 應(yīng)被重載為 A 類的成員函數(shù),形參類型應(yīng)該是 oprd2 所屬的類型。n經(jīng)重載后,表達式 oprd1 B oprd2 相當于

5、 oprd1.operator B(oprd2)運算符重載這是理解和應(yīng)用函數(shù)這是理解和應(yīng)用函數(shù)重載的關(guān)鍵重載的關(guān)鍵運算符重載n 將“+”、“-”運算重載為復(fù)數(shù)類的成員函數(shù)。n 規(guī)則:n實部和虛部分別相加減。n 操作數(shù):n兩個操作數(shù)都是復(fù)數(shù)類的對象。運算符重載#include #include using namespace std;using namespace std;class Complex class Complex / /復(fù)數(shù)類定義復(fù)數(shù)類定義 public:public:/外部接口外部接口Complex(double r = 0.0, double i = 0.0) : Comple

6、x(double r = 0.0, double i = 0.0) : m_real(r), m_imag(i) m_real(r), m_imag(i) /構(gòu)造函數(shù)構(gòu)造函數(shù)Complex operator + (const Complex &c2) const;Complex operator + (const Complex &c2) const;/運算符運算符+ +重載成員函數(shù)重載成員函數(shù)Complex operator - (const Complex &c2) const;Complex operator - (const Complex &c2) const;/運算符運算符- -重

7、載成員函數(shù)重載成員函數(shù)void display() const;void display() const;/輸出復(fù)數(shù)輸出復(fù)數(shù)private:private:/私有數(shù)據(jù)成員私有數(shù)據(jù)成員double m_real;double m_real;/復(fù)數(shù)實部復(fù)數(shù)實部double m_imag;double m_imag;/復(fù)數(shù)虛部復(fù)數(shù)虛部;運算符重載/重載運算符函數(shù)實現(xiàn)重載運算符函數(shù)實現(xiàn)Complex Complex:operator + (const Complex &c2) const Complex Complex:operator + (const Complex &c2) const retu

8、rn Complex(m_real + c2.m_real, m_imag + return Complex(m_real + c2.m_real, m_imag + c2.m_imag); c2.m_imag); /創(chuàng)建一個臨時無名對象作為返回值創(chuàng)建一個臨時無名對象作為返回值 /重載運算符函數(shù)實現(xiàn)重載運算符函數(shù)實現(xiàn)Complex Complex:operator - (const Complex &c2) const Complex Complex:operator - (const Complex &c2) const return Complex(m_real - c2.m_real,

9、m_imag - return Complex(m_real - c2.m_real, m_imag - c2.m_imag); c2.m_imag); /創(chuàng)建一個臨時無名對象作為返回值創(chuàng)建一個臨時無名對象作為返回值 void Complex:display() const void Complex:display() const cout ( m_real , m_imag ) cout ( m_real , m_imag ) endl; endl; 運算符重載int main() int main() /主函數(shù)主函數(shù)Complex c1(5, 4), c2(2, 10), c3;Compl

10、ex c1(5, 4), c2(2, 10), c3;/定義復(fù)數(shù)類的對象定義復(fù)數(shù)類的對象cout c1 = ; c1.display();cout c1 = ; c1.display();cout c2 = ; c2.display();cout c2 = ; c2.display();c3 = c1 - c2;c3 = c1 - c2;/使用重載運算符完成復(fù)數(shù)減法使用重載運算符完成復(fù)數(shù)減法cout c3 = c1 - c2 = ; c3.display();cout c3 = c1 - c2 = ; c3.display();c3 = c1 + c2;c3 = c1 + c2;/使用重載運算

11、符完成復(fù)數(shù)加法使用重載運算符完成復(fù)數(shù)加法cout c3 = c1 + c2 = ; c3.display();cout c3 = c1 + c2 = ; c3.display();return 0;return 0; 程序輸出的結(jié)果為:程序輸出的結(jié)果為:c1 = (5, 4)c1 = (5, 4)c2 = (2, 10)c2 = (2, 10)c3 = c1 - c2 = (3, -6)c3 = c1 - c2 = (3, -6)c3 = c1 + c2 = (7, 14)c3 = c1 + c2 = (7, 14)運算符重載n前置前置單目運算符 Un如果要重載 U 為類成員函數(shù),使之能夠?qū)崿F(xiàn)

12、表達式 U oprd,其中 oprd 為A類對象,則 U 應(yīng)被重載為 A 類的成員函數(shù),無形參n經(jīng)重載后,表達式 U oprd 相當于 oprd.operator U()運算符重載n后置后置單目運算符 +和-n如果要重載 +或-為類成員函數(shù),使之能夠?qū)崿F(xiàn)表達式 oprd+ 或 oprd- ,其中 oprd 為A類對象,則 +或- 應(yīng)被重載為 A 類的成員函數(shù),且具有一個 int 類型形參n經(jīng)重載后,表達式 oprd+ 相當于 oprd.operator +(0)運算符重載n運算符前置+和后置+重載為時鐘類的成員函數(shù)n前置單目運算符,重載函數(shù)沒有形參,對于后置單目運算符,重載函數(shù)需要有一個整型形

13、參n操作數(shù)是時鐘類的對象n實現(xiàn)時間增加1秒鐘運算符重載#include #include using namespace std;using namespace std;class Clockclass Clock / /時鐘類定義時鐘類定義 public:public:/外部接口外部接口Clock(int hour = 0, int minute = 0, int second = 0);Clock(int hour = 0, int minute = 0, int second = 0);void showTime() const;void showTime() const;Clock&

14、operator + ();Clock& operator + ();/前置單目運算符重載前置單目運算符重載Clock operator + (int);Clock operator + (int);/后置單目運算符重載后置單目運算符重載private:private:/私有數(shù)據(jù)成員私有數(shù)據(jù)成員int m_hour, m_minute, m_second;int m_hour, m_minute, m_second;Clock:Clock(int hour/Clock:Clock(int hour/* * = 0 = 0 * */, int minute/, int minute/* * =

15、0 = 0 * */, int second/, int second/* * = 0 = 0 * */) /) if (0 = hour & hour 24 & 0 = minute & minute 60if (0 = hour & hour 24 & 0 = minute & minute 60& 0 = second & second 60) & 0 = second & second m_hour = hour;this-m_hour = hour;this-m_minute = minute;this-m_minute = minute;this-m_second = second

16、;this-m_second = second; else elsecout Time error! endl;cout Time error! endl; 運算符重載void Clock:showTime() const void Clock:showTime() const / /顯示時間函數(shù)顯示時間函數(shù) cout m_hour : m_minute : m_second cout m_hour : m_minute : m_second = 60) if (m_second = 60) m_second -= 60;m_second -= 60;m_minute+;m_minute+;i

17、f (m_minute = 60) if (m_minute = 60) m_minute -= 60;m_minute -= 60;m_hour = (m_hour + 1) % 24;m_hour = (m_hour + 1) % 24; return return * *this;this; /后置單目運算符重載(注意形參表中的整型參數(shù))后置單目運算符重載(注意形參表中的整型參數(shù))ClockClock Clock:operator + ( Clock:operator + (intint) ) Clock old = Clock old = * *this;this;+(+(* *thi

18、s);this);/調(diào)用前置調(diào)用前置“+”+”運算符運算符return old;return old; 這個參數(shù)僅起到標這個參數(shù)僅起到標識的作用,不傳遞識的作用,不傳遞任何參數(shù)值任何參數(shù)值返回的是值,而不是返回的是值,而不是引用引用運算符重載int main() int main() Clock myClock(23, 59, 59);Clock myClock(23, 59, 59);cout First time output: ;cout First time output: ;myClock.showTime();myClock.showTime();cout Show myClock

19、+: ;cout Show myClock+: ;(myClock+).showTime();(myClock+).showTime();cout Show +myClock: ;cout Show +myClock: ;(+myClock).showTime();(+myClock).showTime();return 0;return 0; 運行結(jié)果:運行結(jié)果:First time output: 23:59:59First time output: 23:59:59Show myClock+: 23:59:59Show myClock+: 23:59:59Show +myClock: 0

20、:0:1Show +myClock: 0:0:1運算符重載n函數(shù)的形參代表依自左至右次序排列的各操作數(shù)n后置單目運算符 +和-的重載函數(shù),形參列表中要增加一個int,但不必寫形參名n如果在運算符的重載函數(shù)中需要操作某類對象的私有成員,可以將此函數(shù)聲明為該類的友元運算符重載n雙目運算符 B重載后,表達式oprd1 B oprd2 等同于operator B(oprd1,oprd2 )n前置單目運算符 B重載后,表達式 B oprd 等同于operator B(oprd )n后置單目運算符 +和-重載后,表達式 oprd B 等同于operator B(oprd,0 )運算符重載n將+、-(雙目)

21、重載為非成員函數(shù),并將其聲明為復(fù)數(shù)類的友元,兩個操作數(shù)都是復(fù)數(shù)類的常引用n將(雙目)重載為非成員函數(shù),并將其聲明為復(fù)數(shù)類的友元,它的左操作數(shù)是std:ostream引用,右操作數(shù)為復(fù)數(shù)類的常引用,返回std:ostream引用,用以支持下面形式的輸出:cout a b;該輸出調(diào)用的是:operator (operator (cout, a), b);運算符重載#include #include using namespace std;using namespace std;class Complex class Complex / /復(fù)數(shù)類定義復(fù)數(shù)類定義 public:public:/外部接口

22、外部接口Complex(double r = 0.0, double i = 0.0) : m_real(r), Complex(double r = 0.0, double i = 0.0) : m_real(r), m_imag(i) m_imag(i) /構(gòu)造函數(shù)構(gòu)造函數(shù)friend Complex operator + (const Complex &c1, const Complex friend Complex operator + (const Complex &c1, const Complex &c2);&c2);/運算符運算符+ +重載重載friend Complex op

23、erator - (const Complex &c1, const Complex friend Complex operator - (const Complex &c1, const Complex &c2);&c2);/運算符運算符- -重載重載friend ostream & operator (ostream &out, const Complex friend ostream & operator (ostream &out, const Complex &c);&c); / /運算符運算符重載重載private:private:/私有數(shù)據(jù)成員私有數(shù)據(jù)成員double m_rea

24、l;double m_real;/復(fù)數(shù)實部復(fù)數(shù)實部double m_imag;double m_imag;/復(fù)數(shù)虛部復(fù)數(shù)虛部;/重載運算符函數(shù)實現(xiàn)重載運算符函數(shù)實現(xiàn)Complex operator + (const Complex &c1, const Complex &c2) Complex operator + (const Complex &c1, const Complex &c2) return Complex(c1.m_real + c2.m_real, c1.m_imag + return Complex(c1.m_real + c2.m_real, c1.m_imag + c2

25、.m_imag); c2.m_imag); 運算符重載/重載運算符函數(shù)實現(xiàn)重載運算符函數(shù)實現(xiàn)Complex operator - (const Complex &c1, const Complex &c2) Complex operator - (const Complex &c1, const Complex &c2) return Complex(c1.m_real - c2.m_real, c1.m_imag - return Complex(c1.m_real - c2.m_real, c1.m_imag - c2.m_imag); c2.m_imag); /重載運算符函數(shù)實現(xiàn)重載運算

26、符函數(shù)實現(xiàn)ostream & operator (ostream &out, const Complex &c) ostream & operator (ostream &out, const Complex &c) out ( c.m_real , c.m_imag );out ( c.m_real , c.m_imag );return out;return out; int main() int main() / /主函數(shù)主函數(shù) Complex c1(5, 4), c2(2, 10), c3;Complex c1(5, 4), c2(2, 10), c3;/定義復(fù)數(shù)類的對象定義復(fù)數(shù)類的對

27、象cout c1 = cout c1 = c1 c1 endl; endl;cout c2 = cout c2 = c2 c2 endl; endl;c3 = c1 - c2;c3 = c1 - c2;/使用重載運算符完成復(fù)數(shù)減法使用重載運算符完成復(fù)數(shù)減法cout c3 = c1 - c2 = cout c3 = c1 - c2 = c3 c3 endl; endl;c3 = c1 + c2;c3 = c1 + c2;/使用重載運算符完成復(fù)數(shù)加法使用重載運算符完成復(fù)數(shù)加法cout c3 = c1 + c2 = cout c3 = c1 + c2 = c3 c3 endl; endl;retur

28、n 0;return 0; 多態(tài)性多態(tài)性概述多態(tài)性概述運算符重載運算符重載虛函數(shù)與多態(tài)虛函數(shù)與多態(tài)虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)純虛函數(shù)與抽象類純虛函數(shù)與抽象類程序?qū)嵗绦驅(qū)嵗鄳B(tài)類型小結(jié)多態(tài)類型小結(jié)運行時類型識別運行時類型識別綜合實例綜合實例虛函數(shù)與多態(tài)n回顧前面?zhèn)€人銀行賬戶的例子,其中遺留了一個問題:如何利用一個循環(huán)結(jié)構(gòu)依次處理同一類族中不同類的對象?虛函數(shù)與多態(tài)#include account.h#include account.h#include #include using namespace std;using namespace std;int main() int main() Date

29、 date(2008, 11, 1);Date date(2008, 11, 1); /起始日期起始日期/建立幾個賬戶建立幾個賬戶SavingsAccount sa1(date, S3755217, 0.015);SavingsAccount sa1(date, S3755217, 0.015);SavingsAccount sa2(date, 02342342, 0.015);SavingsAccount sa2(date, 02342342, 0.015);CreditAccount ca(date, C5392394, 10000, 0.0005, 50);CreditAccount c

30、a(date, C5392394, 10000, 0.0005, 50);Account Account * *accounts = &sa1, &sa2, &ca;accounts = &sa1, &sa2, &ca;const int n = sizeof(accounts) / sizeof(Account const int n = sizeof(accounts) / sizeof(Account * *););for (int i=0; in; i+)for (int i=0; ishow();accountsi-show();coutendl;coutshow()調(diào)用的函數(shù)都是A

31、ccount類中定義的show函數(shù)n而我們希望根據(jù)accountsi所指向的實例類型決定哪個show函數(shù)被調(diào)用,當i=2時被調(diào)用的應(yīng)當是CreditAccount類中定義的show函數(shù)n要解決這一問題,就要應(yīng)用虛函數(shù)來實現(xiàn)多態(tài)性虛函數(shù)與多態(tài)n注意區(qū)分“指針類型”與“指針所指實例類型”,后者可以是前者的子類型n“靜態(tài)綁定”是指根據(jù)“指針類型”在編譯時決定要調(diào)用的函數(shù);“動態(tài)綁定”是指根據(jù)“指針所指實例類型”在運行時決定要調(diào)用的函數(shù)n根據(jù)類型兼容規(guī)則,基類指針(或引用)可以指向其派生類的實例,但通過基類指針(或引用)卻只能調(diào)用基類的函數(shù)成員,無法調(diào)用其所指實例(派生類)的函數(shù)成員n解決這一問題的辦

32、法是:如果希望通過基類指針(或引用)訪問其所指派生類實例的函數(shù)成員,則應(yīng)在基類中聲明同名的虛擬函數(shù)成員,表示對相應(yīng)的函數(shù)進行動態(tài)綁定,而不是靜態(tài)綁定虛函數(shù)與多態(tài)nC+中引入了虛函數(shù)的機制在派生類中可以對基類中的成員函數(shù)進行覆蓋(重定義)n虛函數(shù)必須是非靜態(tài)成員函數(shù)n虛函數(shù)的聲明virtual 函數(shù)類型 函數(shù)名(形參表) 函數(shù)體virtual關(guān)鍵字只能出現(xiàn)關(guān)鍵字只能出現(xiàn)在類定義中的函數(shù)原型在類定義中的函數(shù)原型聲明中,不能出現(xiàn)在類聲明中,不能出現(xiàn)在類體外的函數(shù)定義中。體外的函數(shù)定義中。注意,不同于注意,不同于“隱藏隱藏”的概念的概念虛函數(shù)與多態(tài)#include #include using nam

33、espace std;using namespace std;class Base1 class Base1 / /基類基類Base1Base1定義定義 public:public:virtual void display() const;virtual void display() const;/虛函數(shù)虛函數(shù);void Base1:display() const void Base1:display() const cout Base1:display() endl;cout Base1:display() endl; class Base2:public Base1 class Base2

34、:public Base1 / /公有派生類公有派生類Base2Base2定義定義 public:public:void display() const;void display() const;/覆蓋基類的虛函數(shù)覆蓋基類的虛函數(shù);void Base2:display() const void Base2:display() const cout Base2:display() endl;cout Base2:display() endl; 注意,派生類中的虛函數(shù)注意,派生類中的虛函數(shù)可以不用增加可以不用增加virtual關(guān)鍵關(guān)鍵字。對于基類中的虛函數(shù),字。對于基類中的虛函數(shù),派生類中的派生類

35、中的同名同參數(shù)函同名同參數(shù)函數(shù)數(shù)自動成為虛函數(shù)。自動成為虛函數(shù)。虛函數(shù)與多態(tài)class Derived: public Base2 class Derived: public Base2 / /公有派生類公有派生類 public:public:void display() const; void display() const; /覆蓋基類的虛函數(shù)覆蓋基類的虛函數(shù);void Derived:display() const void Derived:display() const cout Derived:display() endl;cout Derived:display() display

36、();ptr-display(); /對象指針對象指針-成員名成員名 int main() int main() / /主函數(shù)主函數(shù) Base1 base1;Base1 base1;/定義定義Base1Base1類對象類對象Base2 base2;Base2 base2;/定義定義Base2Base2類對象類對象Derived derived;Derived derived;/定義定義DerivedDerived類對象類對象fun(&base1);fun(&base1);/用用Base1Base1對象的指針調(diào)用對象的指針調(diào)用funfun函數(shù)函數(shù)fun(&base2);fun(&base2);/

37、用用Base2Base2對象的指針調(diào)用對象的指針調(diào)用funfun函數(shù)函數(shù)fun(&derived);fun(&derived);/用用DerivedDerived對象的指針調(diào)用對象的指針調(diào)用funfun函數(shù)函數(shù)return 0;return 0; 運行結(jié)果:運行結(jié)果:Base1:display()Base1:display()Base2:display()Base2:display()Derived:display()Derived:display()注意,實際調(diào)用的函數(shù)注意,實際調(diào)用的函數(shù)不是由不是由指針類型指針類型決定的,決定的,而是由指針所指的而是由指針所指的派生派生類實例類實例決定的決

38、定的虛函數(shù)與多態(tài)n同名隱藏規(guī)則對于虛函數(shù)來說仍然有效,并且規(guī)則不變n當基類構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用虛函數(shù)時,不會調(diào)用派生類的虛函數(shù)。這是因為當基類被構(gòu)造時,對象還不是一個派生類對象;當基類被析構(gòu)時,對象已經(jīng)不是一個派生類對象n一般不要重寫繼承而來的非虛函數(shù)(雖然語法對此沒有強行限制),因為那會導(dǎo)致通過基類指針和派生類的指針或?qū)ο笳{(diào)用同名函數(shù)時,產(chǎn)生不同的結(jié)果,從而引起混亂虛函數(shù)與多態(tài)n在重寫繼承來的虛函數(shù)時,如果函數(shù)有默認形參值,不要重新定義不同的值。原因是,雖然虛函數(shù)是動態(tài)綁定的,但默認形參值卻是靜態(tài)綁定的。也就是說,默認形參值只能來自基類的定義。n只有通過基類的指針或引用調(diào)用虛函數(shù)時,才會發(fā)

39、生動態(tài)綁定;通過基類的對象調(diào)用虛函數(shù)時,不會發(fā)生動態(tài)綁定。這是因為,基類的指針和引用可以指向派生類的對象,但基類的對象卻不能表示派生類的對象。例如:Derived d;Derived d;/定義派生類對象定義派生類對象Base Base * *ptr = &d;ptr = &d;/基類指針基類指針ptrptr可以指向派生類對象可以指向派生類對象Base &ref = d;Base &ref = d;/基類引用基類引用refref可以作為派生類對象的別名可以作為派生類對象的別名Base b = d;Base b = d;/調(diào)用調(diào)用BaseBase的復(fù)制構(gòu)造函數(shù)用的復(fù)制構(gòu)造函數(shù)用d d構(gòu)造構(gòu)造b

40、b,b b的類型是的類型是BaseBase而非而非DerivedDerived對象切片對象切片:由于執(zhí)行的是:由于執(zhí)行的是Base的復(fù)制構(gòu)造函數(shù),只有的復(fù)制構(gòu)造函數(shù),只有Base類的數(shù)據(jù)成員會類的數(shù)據(jù)成員會被復(fù)制,被復(fù)制,Derived類中新增的數(shù)據(jù)成員既不會被復(fù)制,也沒有空間去存儲。類中新增的數(shù)據(jù)成員既不會被復(fù)制,也沒有空間去存儲。虛函數(shù)與多態(tài)#include #include using namespace std;using namespace std;class Base1 class Base1 / /基類基類Base1Base1定義定義 public:public:virtual

41、void display() const;virtual void display() const;/虛函數(shù)虛函數(shù);void Base1:display() const void Base1:display() const cout Base1:display() endl;cout Base1:display() endl; class Base2:public Base1 class Base2:public Base1 / /公有派生類公有派生類Base2Base2定義定義 public:public:void display() const;void display() const;/

42、覆蓋基類的虛函數(shù)覆蓋基類的虛函數(shù);void Base2:display() const void Base2:display() const cout Base2:display() endl;cout Base2:display() endl; 虛函數(shù)與多態(tài)class Derived: public Base2 class Derived: public Base2 / /公有派生類公有派生類 public:public:void display() const; void display() const; /覆蓋基類的虛函數(shù)覆蓋基類的虛函數(shù);void Derived:display() c

43、onst void Derived:display() const cout Derived:display() endl;cout Derived:display() -成員名成員名 int main() int main() / /主函數(shù)主函數(shù) Base1 base1;Base1 base1;/定義定義Base1Base1類對象類對象Base2 base2;Base2 base2;/定義定義Base2Base2類對象類對象Derived derived;Derived derived;/定義定義DerivedDerived類對象類對象fun(base1);fun(base1);/用用Bas

44、e1Base1對象的指針調(diào)用對象的指針調(diào)用funfun函數(shù)函數(shù)fun(base2);fun(base2);/用用Base2Base2對象的指針調(diào)用對象的指針調(diào)用funfun函數(shù)函數(shù)fun(derived);fun(derived);/用用DerivedDerived對象的指針調(diào)用對象的指針調(diào)用funfun函數(shù)函數(shù)return 0;return 0; 運行結(jié)果:運行結(jié)果:Base1:display()Base1:display()Base1:display()Base1:display()Base1:display()Base1:display()注意,用注意,用基類對象基類對象無法無法形成動態(tài)

45、綁定形成動態(tài)綁定虛函數(shù)與多態(tài)n重載、覆蓋與隱藏n成員函數(shù)被重載的特征:n相同的范圍(在同一個類中)n函數(shù)名相同n函數(shù)參數(shù)個數(shù)或類型不同nvirtual關(guān)鍵字可有可無n覆蓋是指派生類的虛函數(shù)覆蓋基類的虛函數(shù),特征是:n不同的范圍(分別位于派生類和基類)n函數(shù)名字相同n函數(shù)參數(shù)相同n基類的被覆蓋函數(shù)必須有virtual關(guān)鍵字虛函數(shù)與多態(tài)n成員函數(shù)被隱藏的特征是:n不同的范圍(分別位于派生類和基類)n函數(shù)名字相同n函數(shù)參數(shù)可以相同,也可以不同nvirtual關(guān)鍵字可有可無n基類中的同名函數(shù)在派生類中不可見(即被隱藏,除非用域操作符指定基類類型)從內(nèi)向外尋找函數(shù)名從內(nèi)向外尋找函數(shù)名多態(tài)性多態(tài)性概述多態(tài)

46、性概述運算符重載運算符重載虛函數(shù)與多態(tài)虛函數(shù)與多態(tài)虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)純虛函數(shù)與抽象類純虛函數(shù)與抽象類程序?qū)嵗绦驅(qū)嵗鄳B(tài)類型小結(jié)多態(tài)類型小結(jié)運行時類型識別運行時類型識別綜合實例綜合實例虛析構(gòu)函數(shù)為什么需要虛析構(gòu)函數(shù)?n可能通過基類指針刪除派生類對象n如果你打算允許其他人通過基類指針調(diào)用對象的析構(gòu)函數(shù)(通過delete這樣做是正常的),就需要讓基類的析構(gòu)函數(shù)成為虛函數(shù),否則執(zhí)行delete的結(jié)果是不確定的虛析構(gòu)函數(shù)#include #include using namespace std;using namespace std;class Base class Base public:publ

47、ic:Base();Base();Base:Base() Base:Base() cout Base destructor cout Base destructor endl;endl; class Derived: public Baseclass Derived: public Base public:public:Derived();Derived();Derived();Derived();private:private:int int * *p;p;Derived:Derived() Derived:Derived() p = new int(0);p = new int(0); D

48、erived:Derived() Derived:Derived() cout Derived cout Derived destructor endl;destructor endl;delete p;delete p; void fun(Basevoid fun(Base* * b) b) delete b;delete b; int main() int main() Base Base * *b = new Derived();b = new Derived();fun(b);fun(b);return 0;return 0; 虛析構(gòu)函數(shù)n運行時結(jié)果:nBase destructorn

49、避免上述錯誤的有效方法就是將析構(gòu)函數(shù)聲明為虛函數(shù),運行結(jié)果變?yōu)椋簄Derived destructornBase destructor虛析構(gòu)函數(shù)#include #include using namespace std;using namespace std;class Base class Base public:public:virtualvirtual Base(); Base();Base:Base() Base:Base() cout Base destructor cout Base destructor endl;endl; class Derived: public Basec

50、lass Derived: public Base public:public:Derived();Derived();Derived();Derived();private:private:int int * *p;p;Derived:Derived() Derived:Derived() p = new int(0);p = new int(0); Derived:Derived() Derived:Derived() cout Derived cout Derived destructor endl;destructor endl;delete p;delete p; void fun(

51、Basevoid fun(Base* * b) b) delete b;delete b; int main() int main() Base Base * *b = new Derived();b = new Derived();fun(b);fun(b);return 0;return 0; 多態(tài)性多態(tài)性概述多態(tài)性概述運算符重載運算符重載虛函數(shù)與多態(tài)虛函數(shù)與多態(tài)虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)純虛函數(shù)與抽象類純虛函數(shù)與抽象類程序?qū)嵗绦驅(qū)嵗鄳B(tài)類型小結(jié)多態(tài)類型小結(jié)運行時類型識別運行時類型識別綜合實例綜合實例純虛函數(shù)與抽象類n純虛函數(shù)是一個在基類中聲明的虛函數(shù),它在該基類中沒有定義具體的操作內(nèi)容,要求

52、各派生類根據(jù)實際需要定義自己的版本,純虛函數(shù)的聲明格式為:virtual 函數(shù)類型 函數(shù)名(參數(shù)表) = 0;n帶有純虛函數(shù)的類稱為抽象類,這樣的類不可實例化:class 類名 virtual 類型 函數(shù)名(參數(shù)表)=0; /純虛函數(shù) .純虛函數(shù)的作用:純虛函數(shù)的作用:1)表示相應(yīng)的類為抽象類,不可實例化;)表示相應(yīng)的類為抽象類,不可實例化;2)支持通過抽象類指針實現(xiàn)對應(yīng)函數(shù)的動態(tài)綁定)支持通過抽象類指針實現(xiàn)對應(yīng)函數(shù)的動態(tài)綁定(即多態(tài)即多態(tài))。純虛函數(shù)與抽象類n作用n抽象類為抽象和設(shè)計的目的而聲明,將有關(guān)的數(shù)據(jù)和行為組織在一個繼承層次結(jié)構(gòu)中,保證派生類具有要求的行為。n對于暫時無法實現(xiàn)的函數(shù),

53、可以聲明為純虛函數(shù),留給派生類去實現(xiàn)。n注意n抽象類只能作為基類來使用n不能聲明抽象類的對象n析構(gòu)函數(shù)可以是虛函數(shù),但構(gòu)造函數(shù)不能是虛函數(shù)抽象類相當于一個抽象類相當于一個“半成品半成品”,它為派生類的實現(xiàn)提供基礎(chǔ),但它為派生類的實現(xiàn)提供基礎(chǔ),但自己不可以用于產(chǎn)品實現(xiàn)。自己不可以用于產(chǎn)品實現(xiàn)。純虛函數(shù)與抽象類#include #include using namespace std;using namespace std;class Base1 class Base1 / /基類基類Base1Base1定義定義 public:public:virtual void display() const

54、 = 0;virtual void display() const = 0;/純虛函數(shù)純虛函數(shù);class Base2: class Base2: public Base1 public Base1 / /公有派生類公有派生類Base2Base2定義定義 public:public:void display() const;void display() const;/覆蓋基類的虛函數(shù)覆蓋基類的虛函數(shù);void Base2:display() const void Base2:display() const cout Base2:display() endl;cout Base2:display

55、() endl; 純虛函數(shù)與抽象類class Derived: class Derived: public Base2 public Base2 / /公有派生類公有派生類DerivedDerived定義定義 public:public:void display() const;void display() const;/覆蓋基類的虛函數(shù)覆蓋基類的虛函數(shù);void Derived:display() const void Derived:display() const cout Derived:display() endl;cout Derived:display() display();pt

56、r-display(); /對象指針對象指針-成員名成員名 int main() int main() / /主函數(shù)主函數(shù) Base2 base2;Base2 base2;/定義定義Base2Base2類對象類對象Derived derived;Derived derived;/定義定義DerivedDerived類對象類對象fun(&base2);fun(&base2);/用用Base2Base2對象的指針調(diào)用對象的指針調(diào)用funfun函數(shù)函數(shù)fun(&derived);fun(&derived);/用用DerivedDerived對象的指針調(diào)用對象的指針調(diào)用funfun函數(shù)函數(shù)return

57、 0;return 0; 運行結(jié)果:運行結(jié)果:Base2:display()Base2:display()Derived:display()Derived:display()多態(tài)性多態(tài)性概述多態(tài)性概述運算符重載運算符重載虛函數(shù)與多態(tài)虛函數(shù)與多態(tài)虛析構(gòu)函數(shù)虛析構(gòu)函數(shù)純虛函數(shù)與抽象類純虛函數(shù)與抽象類程序?qū)嵗绦驅(qū)嵗鄳B(tài)類型小結(jié)多態(tài)類型小結(jié)運行時類型識別運行時類型識別綜合實例綜合實例程序?qū)嵗儾介L梯形積分算法求解函數(shù)的定積分n我們只考慮最簡單的情況,設(shè)被積函數(shù)是一個一元函數(shù),定積分表達式為:n積分表示的意義是一元函數(shù)f(x)在區(qū)間a到b之間與x軸所夾的面積( )dbaIf xxy xabxkxk-1

58、hIkf(x)程序?qū)嵗儾介L梯形積分算法求解函數(shù)的定積分n在每個小區(qū)間上都用小的梯形面積來近似原函數(shù)的積分,當小區(qū)間足夠小時,我們就可以得到原來積分的近似值。每個小區(qū)間的面積值公式:n實際計算中步長h逐次減半,反復(fù)利用上述求積公式進行計算,直到所求得的積分結(jié)果滿足要求的精度為止。并得到遞推公式:-110 ()()2nnkkkhTf xf x-121021()22nnnkkhTTf x程序?qū)嵗儾介L梯形積分算法求解函數(shù)的定積分MyFunction + operator()(x : double) : doubleIntegration + operator ()(a : double, b :

59、double, eps : double) : doubleFunction + operator ()(x : double) : doubleTrapz+ Trapz(pf : const F&) + operator ()(a : double, b : double, eps : double) : double-f程序?qū)嵗儾介L梯形積分算法求解函數(shù)的定積分n我們求一個測試函數(shù)在某給定區(qū)間的積分值,對整個程序進行了測試,誤差為10-7。n測試函數(shù):n整個程序分為三個獨立的文件,Trapzint.h文件包括類的定義,Trapzint.cpp文件包括類的成員函數(shù)實現(xiàn)。文件intmain.c

60、pp是程序的主函數(shù),主函數(shù)中定義了函數(shù)類Fun和梯形積分類Trapz的對象221log(1)d1xIxx程序?qū)嵗儾介L梯形積分算法求解函數(shù)的定積分/Trapzint.h /Trapzint.h 文件一,類定義文件一,類定義class Function class Function / /抽象類抽象類FunctionFunction的定義的定義 public:public:virtual double operator () (double x) const = 0;virtual double operator () (double x) const = 0;/純虛函純虛函數(shù)重載運算符數(shù)重載運

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論