C進(jìn)階課程講義筆記(干貨)_第1頁
C進(jìn)階課程講義筆記(干貨)_第2頁
C進(jìn)階課程講義筆記(干貨)_第3頁
C進(jìn)階課程講義筆記(干貨)_第4頁
C進(jìn)階課程講義筆記(干貨)_第5頁
已閱讀5頁,還剩236頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、傳智播客C+進(jìn)階課程講義 函數(shù)模板和類模板前言C+提供了函數(shù)模板(function template)。所謂函數(shù)模板,實(shí)際上是建立一個(gè)通用函數(shù),其函數(shù)類型和形參類型不具體指定,用一個(gè)虛擬的類型來代表。這個(gè)通用函數(shù)就稱為函數(shù)模板。凡是函數(shù)體相同的函數(shù)都可以用這個(gè)模板來代替,不必定義多個(gè)函數(shù),只需在模板中定義一次即可。在調(diào)用函數(shù)時(shí)系統(tǒng)會(huì)根據(jù)實(shí)參的類型來取代模板中的虛擬類型,從而實(shí)現(xiàn)了不同函數(shù)的功能。1)C+提供兩種模板機(jī)制:函數(shù)模板、類模板2)類屬 類型參數(shù)化,又稱參數(shù)模板使得程序(算法)可以從邏輯功能上抽象,把被處理的對(duì)象(數(shù)據(jù))類型作為參數(shù)傳遞??偨Y(jié):模板把函數(shù)或類要處理的數(shù)據(jù)類型參數(shù)化,表現(xiàn)

2、為參數(shù)的多態(tài)性,稱為類屬。模板用于表達(dá)邏輯結(jié)構(gòu)相同,但具體數(shù)據(jù)元素類型不同的數(shù)據(jù)對(duì)象的通用行為。6.1函數(shù)模板6.1.1為什么要有函數(shù)模板 需求:寫n個(gè)函數(shù),交換char類型、int類型、double類型變量的值。案例:#include using namespace std;/*void myswap(int &a, int &b)int t = a;a = b;b = t;void myswap(char &a, char &b)char t = a;a = b;b = t;*/template 關(guān)鍵字告訴C+編譯器 我要開始泛型了.你不要隨便報(bào)錯(cuò) /數(shù)據(jù)類型T 參數(shù)化數(shù)據(jù)類型templa

3、te void myswap(T &a, T &b)T t;t = a;a = b;b = t;void main()/char a = c;int x = 1;int y = 2;myswap(x, y); /自動(dòng)數(shù)據(jù)類型 推導(dǎo)的方式 float a = 2.0;float b = 3.0;myswap(a, b); /自動(dòng)數(shù)據(jù)類型 推導(dǎo)的方式 myswap(a, b); /顯示類型調(diào)用 couthello.endl;system(pause);return ;6.1.2函數(shù)模板語法函數(shù)模板定義形式 template 類型形式參數(shù)的形式為:typename T1 , typename T2

4、, , typename Tn 或class T1 , class T2 , , class Tn 函數(shù)模板調(diào)用 myswap(a, b); /顯示類型調(diào)用myswap(a, b); /自動(dòng)數(shù)據(jù)類型推導(dǎo) 6.1.3函數(shù)模板和模板函數(shù)6.1.4函數(shù)模板做函數(shù)參數(shù)#include using namespace std;templatevoid sortArray(T *a, T2 num)T tmp ;int i, j ;for (i=0; inum; i+)for (j=i+1; jnum; j+)if (ai aj)tmp = ai;ai = aj;aj = tmp;templatevoid

5、 pirntArray(T *a, int num)int i = 0;for (i=0; inum; i+)coutai ;void main()int num = 0;char a = ddadeeettttt;num = strlen(a);printf(排序之前n);pirntArray(a, num);sortArray(a, num); /顯示類型調(diào)用 模板函數(shù) printf(排序之后n);pirntArray(a, num);couthello.endl;system(pause);return ;6.1.5函數(shù)模板遇上函數(shù)重載函數(shù)模板和普通函數(shù)區(qū)別結(jié)論: /*函數(shù)模板不允許自動(dòng)

6、類型轉(zhuǎn)化普通函數(shù)能夠進(jìn)行自動(dòng)類型轉(zhuǎn)換*/函數(shù)模板和普通函數(shù)在一起,調(diào)用規(guī)則: /*1 函數(shù)模板可以像普通函數(shù)一樣被重載2 C+編譯器優(yōu)先考慮普通函數(shù)3 如果函數(shù)模板可以產(chǎn)生一個(gè)更好的匹配,那么選擇模板4 可以通過空模板實(shí)參列表的語法限定編譯器只通過模板匹配*/案例1:#include using namespace std;template void myswap(T &a, T &b)T t;t = a;a = b;b = t;coutmyswap 模板函數(shù)doendl;void myswap(char &a, int &b)int t;t = a;a = b;b = t;coutmyswa

7、p 普通函數(shù)doendl;void main()char cData = a;int iData = 2;/myswap(cData, iData); /結(jié)論 函數(shù)模板不提供隱式的數(shù)據(jù)類型轉(zhuǎn)換 必須是嚴(yán)格的匹配myswap(cData, iData); /myswap(iData, cData);couthello.endl;system(pause);return ;案例2: #include iostreamusing namespace std;int Max(int a, int b)coutint Max(int a, int b) b ? a : b;templateT Max(T

8、 a, T b)coutT Max(T a, T b) b ? a : b;templateT Max(T a, T b, T c)coutT Max(T a, T b, T c)endl;return Max(Max(a, b), c);void main()int a = 1;int b = 2;coutMax(a, b)endl; /當(dāng)函數(shù)模板和普通函數(shù)都符合調(diào)用時(shí),優(yōu)先選擇普通函數(shù)coutMax(a, b)endl; /若顯示使用函數(shù)模板,則使用 類型列表coutMax(3.0, 4.0)endl; /如果 函數(shù)模板產(chǎn)生更好的匹配 使用函數(shù)模板coutMax(5.0, 6.0, 7.0

9、)endl; /重載coutMax(a, 100)endl; /調(diào)用普通函數(shù) 可以隱式類型轉(zhuǎn)換 system(pause);return ;6.1.6 C+編譯器模板機(jī)制剖析思考:為什么函數(shù)模板可以和函數(shù)重載放在一塊。C+編譯器是如何提供函數(shù)模板機(jī)制的?編譯器編譯原理什么是gcc gcc(GNU C Compiler)編譯器的作者是Richard Stallman,也是GNU項(xiàng)目的奠基者。什么是gcc:gcc是GNU Compiler Collection的縮寫。最初是作為C語言的編譯器(GNU C Compiler),現(xiàn)在已經(jīng)支持多種語言了,如C、C+、Java、Pascal、Ada、COB

10、OL語言等。gcc支持多種硬件平臺(tái),甚至對(duì)Don Knuth 設(shè)計(jì)的 MMIX 這類不常見的計(jì)算機(jī)都提供了完善的支持gcc主要特征 1)gcc是一個(gè)可移植的編譯器,支持多種硬件平臺(tái)2)gcc不僅僅是個(gè)本地編譯器,它還能跨平臺(tái)交叉編譯。3)gcc有多種語言前端,用于解析不同的語言。4)gcc是按模塊化設(shè)計(jì)的,可以加入新語言和新CPU架構(gòu)的支持5)gcc是自由軟件gcc編譯過程 預(yù)處理(Pre-Processing)編譯(Compiling)匯編(Assembling)鏈接(Linking)Gcc *.c o 1exe (總的編譯步驟)Gcc E 1.c o 1.i /宏定義 宏展開Gcc S 1

11、.i o 1.s Gcc c 1.s o 1.o Gcc 1.o o 1exe結(jié)論:gcc編譯工具是一個(gè)工具鏈。hello程序是一個(gè)高級(jí)語言程序,這種形式容易被人讀懂。為了在系統(tǒng)上運(yùn)行hello.c程序,每條語句都必須轉(zhuǎn)化為低級(jí)機(jī)器指令。然后將這些指令打包成可執(zhí)行目標(biāo)文件格式,并以二進(jìn)制形式存儲(chǔ)器于磁盤中。gcc常用編譯選項(xiàng) 選項(xiàng)作用-o產(chǎn)生目標(biāo)(.i、.s、.o、可執(zhí)行文件等)-c通知gcc取消鏈接步驟,即編譯源碼并在最后生成目標(biāo)文件-E只運(yùn)行C預(yù)編譯器-S告訴編譯器產(chǎn)生匯編語言文件后停止編譯,產(chǎn)生的匯編語言文件擴(kuò)展名為.s-Wall使gcc對(duì)源文件的代碼有問題的地方發(fā)出警告-Idir將di

12、r目錄加入搜索頭文件的目錄路徑-Ldir將dir目錄加入搜索庫的目錄路徑-llib鏈接lib庫-g在目標(biāo)文件中嵌入調(diào)試信息,以便gdb之類的調(diào)試程序調(diào)試練習(xí) gcc -E hello.c -o hello.i(預(yù)處理)gcc -S hello.i -o hello.s(編譯)gcc -c hello.s -o hello.o(匯編)gcc hello.o -o hello(鏈接)以上四個(gè)步驟,可合成一個(gè)步驟gcc hello.c -o hello(直接編譯鏈接成可執(zhí)行目標(biāo)文件)gcc -c hello.c或gcc -c hello.c -o hello.o(編譯生成可重定位目標(biāo)文件)建議初學(xué)都

13、加這個(gè)選項(xiàng)。下面這個(gè)例子如果不加-Wall選項(xiàng)編譯器不報(bào)任何錯(cuò)誤,但是得到的結(jié)果卻不是預(yù)期的。#include int main(void) printf(2+1 is %f, 3); return 0;Gcc編譯多個(gè).chello_1.hhello_1.cmain.c一次性編譯gcc hello_1.c main.c o newhello獨(dú)立編譯gcc -Wall -c main.c -o main.ogcc -Wall -c hello_1.c -o hello_fn.ogcc -Wall main.o hello_1.o -o newhello模板函數(shù)反匯編觀察 命令:g+ -S 7.c

14、pp -o 7.s.file7.cpp.text.def_ZL6printfPKcz;.scl3;.type32;.endef_ZL6printfPKcz:LFB264:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5pushl%ebxsubl$36, %esp.cfi_offset 3, -12leal12(%ebp), %eaxmovl%eax, -12(%ebp)movl-12(%ebp), %eaxmovl%eax, 4(%esp)movl

15、8(%ebp), %eaxmovl%eax, (%esp)call_mingw_vprintfmovl%eax, %ebxmovl%ebx, %eaxaddl$36, %esppopl%ebx.cfi_restore 3popl%ebp.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endprocLFE264:.lcomm _ZStL8_ioinit,1,1.def_main;.scl2;.type32;.endef.section .rdata,drLC0:.ascii a:%d b:%d 120LC1:.ascii c1:%c c2:%c 120LC2:.as

16、cii pause0.text.globl_main.def_main;.scl2;.type32;.endef_main:LFB1023:.cfi_startproc.cfi_personality 0,_gxx_personality_v0.cfi_lsda 0,LLSDA1023pushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5andl$-16, %espsubl$32, %espcall_mainmovl$0, 28(%esp)movl$10, 24(%esp)movb

17、$97, 23(%esp)movb$98, 22(%esp)leal24(%esp), %eaxmovl%eax, 4(%esp)leal28(%esp), %eaxmovl%eax, (%esp)call_Z6myswapIiEvRT_S1_ /66 =126 movl24(%esp), %edxmovl28(%esp), %eaxmovl%edx, 8(%esp)movl%eax, 4(%esp)movl$LC0, (%esp)call_ZL6printfPKczleal22(%esp), %eaxmovl%eax, 4(%esp)leal23(%esp), %eaxmovl%eax, (

18、%esp)call_Z6myswapIcEvRT_S1_ /77 =155 movzbl22(%esp), %eaxmovsbl%al, %edxmovzbl23(%esp), %eaxmovsbl%al, %eaxmovl%edx, 8(%esp)movl%eax, 4(%esp)movl$LC1, (%esp)call_ZL6printfPKczmovl$LC2, (%esp)LEHB0:call_systemLEHE0:movl$0, %eaxjmpL7L6:movl%eax, (%esp)LEHB1:call_Unwind_ResumeLEHE1:L7:leave.cfi_restor

19、e 5.cfi_def_cfa 4, 4ret.cfi_endprocLFE1023:.def_gxx_personality_v0;.scl2;.type32;.endef.section.gcc_except_table,wLLSDA1023:.byte0 xff.byte0 xff.byte0 x1.uleb128 LLSDACSE1023-LLSDACSB1023LLSDACSB1023:.uleb128 LEHB0-LFB1023.uleb128 LEHE0-LEHB0.uleb128 L6-LFB1023.uleb128 0.uleb128 LEHB1-LFB1023.uleb12

20、8 LEHE1-LEHB1.uleb128 0.uleb128 0LLSDACSE1023:.text.section.text$_Z6myswapIiEvRT_S1_,x.linkonce discard.globl_Z6myswapIiEvRT_S1_.def_Z6myswapIiEvRT_S1_;.scl2;.type32;.endef_Z6myswapIiEvRT_S1_: /126 LFB1024:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_regist

21、er 5subl$16, %espmovl8(%ebp), %eaxmovl(%eax), %eaxmovl%eax, -4(%ebp)movl12(%ebp), %eaxmovl(%eax), %edxmovl8(%ebp), %eaxmovl%edx, (%eax)movl12(%ebp), %eaxmovl-4(%ebp), %edxmovl%edx, (%eax)leave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endprocLFE1024:.section.text$_Z6myswapIcEvRT_S1_,x.linkonce discard.g

22、lobl_Z6myswapIcEvRT_S1_.def_Z6myswapIcEvRT_S1_;.scl2;.type32;.endef_Z6myswapIcEvRT_S1_: /155 LFB1025:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5subl$16, %espmovl8(%ebp), %eaxmovzbl(%eax), %eaxmovb%al, -1(%ebp)movl12(%ebp), %eaxmovzbl(%eax), %edx

23、movl8(%ebp), %eaxmovb%dl, (%eax)movl12(%ebp), %eaxmovzbl-1(%ebp), %edxmovb%dl, (%eax)leave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endprocLFE1025:.text.def_tcf_0;.scl3;.type32;.endef_tcf_0:LFB1027:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5subl$8,

24、 %espmovl$_ZStL8_ioinit, %ecxcall_ZNSt8ios_base4InitD1Evleave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endprocLFE1027:.def_Z41_static_initialization_and_destruction_0ii;.scl3;.type32;.endef_Z41_static_initialization_and_destruction_0ii:LFB1026:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5,

25、-8movl%esp, %ebp.cfi_def_cfa_register 5subl$24, %espcmpl$1, 8(%ebp)jneL11cmpl$65535, 12(%ebp)jneL11movl$_ZStL8_ioinit, %ecxcall_ZNSt8ios_base4InitC1Evmovl$_tcf_0, (%esp)call_atexitL11:leave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endprocLFE1026:.def_GLOBAL_sub_I_main;.scl3;.type32;.endef_GLOBAL_sub_I_

26、main:LFB1028:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5subl$24, %espmovl$65535, 4(%esp)movl$1, (%esp)call_Z41_static_initialization_and_destruction_0iileave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endprocLFE1028:.section.ctors,w.align 4.long_GLOB

27、AL_sub_I_main.identGCC: (rev2, Built by MinGW-builds project) 4.8.0.def_mingw_vprintf;.scl2;.type32;.endef.def_system;.scl2;.type32;.endef.def_Unwind_Resume;.scl2;.type32;.endef.def_ZNSt8ios_base4InitD1Ev;.scl2;.type32;.endef.def_ZNSt8ios_base4InitC1Ev;.scl2;.type32;.endef.def_atexit;.scl2;.type32;.

28、endef函數(shù)模板機(jī)制結(jié)論編譯器并不是把函數(shù)模板處理成能夠處理任意類的函數(shù)編譯器從函數(shù)模板通過具體類型產(chǎn)生不同的函數(shù)編譯器會(huì)對(duì)函數(shù)模板進(jìn)行兩次編譯在聲明的地方對(duì)模板代碼本身進(jìn)行編譯;在調(diào)用的地方對(duì)參數(shù)替換后的代碼進(jìn)行編譯。6.2類模板6.2.1為什么需要類模板類模板與函數(shù)模板的定義和使用類似,我們已經(jīng)進(jìn)行了介紹。 有時(shí),有兩個(gè)或多個(gè)類,其功能是相同的,僅僅是數(shù)據(jù)類型不同,如下面語句聲明了一個(gè)類:類模板用于實(shí)現(xiàn)類所需數(shù)據(jù)的類型參數(shù)化 類模板在表示如數(shù)組、表、圖等數(shù)據(jù)結(jié)構(gòu)顯得特別重要, 這些數(shù)據(jù)結(jié)構(gòu)的表示和算法不受所包含的元素類型的影響6.2.2單個(gè)類模板語法/類的類型參數(shù)化 抽象的類/單個(gè)類模板

29、templateclass A public:A(T t)this-t = t;T &getT()return t;protected:public:T t;void main() /模板了中如果使用了構(gòu)造函數(shù),則遵守以前的類的構(gòu)造函數(shù)的調(diào)用規(guī)則A a(100); a.getT();printAA(a);return ;6.2.3繼承中的類模板語法/結(jié)論: 子類從模板類繼承的時(shí)候,需要讓編譯器知道 父類的數(shù)據(jù)類型具體是什么(數(shù)據(jù)類型的本質(zhì):固定大小內(nèi)存塊的別名)A /class B : public Apublic:B(int i) : A(i)void printB()coutA:tendl

30、;protected:private:;/模板與上繼承/怎么樣從基類繼承 /若基類只有一個(gè)帶參數(shù)的構(gòu)造函數(shù),子類是如何啟動(dòng)父類的構(gòu)造函數(shù)void pintBB(B &b)b.printB();void printAA(A &a) /類模板做函數(shù)參數(shù) /a.getT();void main()A a(100); /模板了中如果使用了構(gòu)造函數(shù),則遵守以前的類的構(gòu)造函數(shù)的調(diào)用規(guī)則 a.getT();printAA(a);B b(10);b.printB();couthello.endl;system(pause);return ;6.2.4類模板語法知識(shí)體系梳理 所有的類模板函數(shù)寫在類的內(nèi)部所有的類

31、模板函數(shù)寫在類的外部,在一個(gè)cpp中/構(gòu)造函數(shù) 沒有問題/普通函數(shù) 沒有問題/友元函數(shù):用友元函數(shù)重載 /friend ostream& operator (ostream &out, Complex &c3) ;/友元函數(shù):友元函數(shù)不是實(shí)現(xiàn)函數(shù)重載(非 )/1)需要在類前增加 類的前置聲明 函數(shù)的前置聲明 templateclass Complex; templateComplex mySub(Complex &c1, Complex &c2);/2)類的內(nèi)部聲明 必須寫成: friend Complex mySub (Complex &c1, Complex &c2);/3)友元函數(shù)實(shí)現(xiàn)

32、必須寫成:template Complex mySub(Complex &c1, Complex &c2)Complex tmp(c1.a - c2.a, c1.b-c2.b);return tmp;/4)友元函數(shù)調(diào)用 必須寫成Complex c4 = mySub(c1, c2);coutc4;結(jié)論:友元函數(shù)只用來進(jìn)行 左移 友移操作符重載。所有的類模板函數(shù)寫在類的外部,在不同的.h和.cpp中,也就是類模板函數(shù)說明和類模板實(shí)現(xiàn)分開/類模板函數(shù)構(gòu)造函數(shù)普通成員函數(shù)友元函數(shù)用友元函數(shù)重載; 用友元函數(shù)重載非/要包含.cpp總結(jié) 歸納以上的介紹,可以這樣聲明和使用類模板:1) 先寫出一個(gè)實(shí)際的類。

33、由于其語義明確,含義清楚,一般不會(huì)出錯(cuò)。2) 將此類中準(zhǔn)備改變的類型名(如int要改變?yōu)閒loat或char)改用一個(gè)自己指定的虛擬類型名(如上例中的numtype)。3) 在類聲明前面加入一行,格式為: template 如: template /注意本行末尾無分號(hào) class Compare ; /類體4) 用類模板定義對(duì)象時(shí)用以下形式: 類模板名 對(duì)象名; 類模板名 對(duì)象名(實(shí)參表列);如: Compare cmp; Compare cmp(3,7);5) 如果在類模板外定義成員函數(shù),應(yīng)寫成類模板形式: template 函數(shù)類型 類模板名:成員函數(shù)名(函數(shù)形參表列) 關(guān)于類模板的幾點(diǎn)說

34、明:1) 類模板的類型參數(shù)可以有一個(gè)或多個(gè),每個(gè)類型前面都必須加class,如: template class someclass ;在定義對(duì)象時(shí)分別代入實(shí)際的類型名,如: someclass obj;2) 和使用類一樣,使用類模板時(shí)要注意其作用域,只能在其有效作用域內(nèi)用它定義對(duì)象。3) 模板可以有層次,一個(gè)類模板可以作為基類,派生出派生模板類。6.2.5類模板中的static關(guān)鍵字 從類模板實(shí)例化的每個(gè)模板類有自己的類模板數(shù)據(jù)成員,該模板類的所有對(duì)象共享一個(gè)static數(shù)據(jù)成員 和非模板類的static數(shù)據(jù)成員一樣,模板類的static數(shù)據(jù)成員也應(yīng)該在文件范圍定義和初始化 每個(gè)模板類有自己的

35、類模板的static數(shù)據(jù)成員副本原理圖:6.3類模板在項(xiàng)目開發(fā)中的應(yīng)用 小結(jié)模板是C+類型參數(shù)化的多態(tài)工具。C+提供函數(shù)模板和類模板。 模板定義以模板說明開始。類屬參數(shù)必須在模板定義中至少出現(xiàn)一次。 同一個(gè)類屬參數(shù)可以用于多個(gè)模板。 類屬參數(shù)可用于函數(shù)的參數(shù)類型、返回類型和聲明函數(shù)中的變量。 模板由編譯器根據(jù)實(shí)際數(shù)據(jù)類型實(shí)例化,生成可執(zhí)行代碼。實(shí)例化的函數(shù)。 模板稱為模板函數(shù);實(shí)例化的類模板稱為模板類。 函數(shù)模板可以用多種方式重載。 類模板可以在類層次中使用 。訓(xùn)練題請(qǐng)?jiān)O(shè)計(jì)一個(gè)數(shù)組模板類( MyVector ),完成對(duì)int、char、Teacher類型元素的管理。 需求 設(shè)計(jì):類模板 構(gòu)造函

36、數(shù) 拷貝構(gòu)造函數(shù) 重載=操作符 a2=a1實(shí)現(xiàn)請(qǐng)仔細(xì)思考:如果數(shù)組模板類中的元素是Teacher元素時(shí),需要Teacher類做什么工作如果數(shù)組模板類中的元素是Teacher元素時(shí),Teacher類含有指針屬性哪?class Teacherfriend ostream & operatorage = age;strcpy(this-name, name);Teacher()this-age = 0;strcpy(this-name, );private:int age;char name32;class Teacherfriend ostream & operatorage = age;strc

37、py(this-name, name);Teacher()this-age = 0;strcpy(this-name, );private:int age;char *pname;結(jié)論1: 如果把Teacher放入到MyVector數(shù)組中,并且Teacher類的屬性含有指針,就是出現(xiàn)深拷貝和淺拷貝的問題。結(jié)論2:需要Teacher封裝的函數(shù)有: 重寫拷貝構(gòu)造函數(shù) 重載等號(hào)操作符 重載左移操作符。理論提高:所有容器提供的都是值(value)語意,而非引用(reference)語意。容器執(zhí)行插入元素的操作時(shí),內(nèi)部實(shí)施拷貝動(dòng)作。所以STL容器內(nèi)存儲(chǔ)的元素必須能夠被拷貝(必須提供拷貝構(gòu)造函數(shù))。請(qǐng)從數(shù)

38、組模板中進(jìn)行派生 /演示從模板類 派生 一般類#include MyVector.cppclass MyArray01 : public MyVectorpublic:MyArray01(int len) : MyVector(len);protected:private:;/演示從模板類 派生 模板類 /BoundArray template class MyArray02 : public MyVectorpublic:MyArray02(int len) : MyVector(len);protected:private:;測試案例:/演示 從模板類 繼承 模板類void main()M

39、yArray02 dArray2(10);dArray21 = 3.15;/演示 從模板類 繼承 一般類void main11()MyArray01 d_array(10);for (int i=0; id_array.getLen(); i+)d_arrayi = 3.15;for (int i=0; id_array.getLen(); i+)cout d_arrayi ;couthello.endl;system(pause);return ;6.4作業(yè)封裝你自己的數(shù)組類;設(shè)計(jì)被存儲(chǔ)的元素為類對(duì)象;思考:類對(duì)象的類,應(yīng)該實(shí)現(xiàn)的功能。/1 優(yōu)化Teacher類, 屬性變成 char *pa

40、nme, 構(gòu)造函數(shù)里面 分配內(nèi)存/2 優(yōu)化Teacher類,析構(gòu)函數(shù) 釋放panme指向的內(nèi)存空間/3 優(yōu)化Teacher類,避免淺拷貝 重載= 重寫拷貝構(gòu)造函數(shù) /4 優(yōu)化Teacher類,在Teacher增加 stl 容器的概念7、C+的類型轉(zhuǎn)換7.1 類型轉(zhuǎn)換名稱和語法C風(fēng)格的強(qiáng)制類型轉(zhuǎn)換(Type Cast)很簡單,不管什么類型的轉(zhuǎn)換統(tǒng)統(tǒng)是:TYPE b = (TYPE)a C+風(fēng)格的類型轉(zhuǎn)換提供了4種類型轉(zhuǎn)換操作符來應(yīng)對(duì)不同場合的應(yīng)用。static_cast靜態(tài)類型轉(zhuǎn)換。如int轉(zhuǎn)換成charreinterpreter_cast重新解釋類型 dynamic_cast命名上理解是動(dòng)態(tài)類

41、型轉(zhuǎn)換。如子類和父類之間的多態(tài)類型轉(zhuǎn)換。const_cast,字面上理解就是去const屬性。4種類型轉(zhuǎn)換的格式:TYPE B = static_cast (a) 7.2 類型轉(zhuǎn)換一般性介紹 1)static_cast()靜態(tài)類型轉(zhuǎn)換,編譯的時(shí)c+編譯器會(huì)做類型檢查;基本類型能轉(zhuǎn)換 但是不能轉(zhuǎn)換指針類型2)若不同類型之間,進(jìn)行強(qiáng)制類型轉(zhuǎn)換,用reinterpret_cast() 進(jìn)行重新解釋3)一般性結(jié)論:C語言中 能隱式類型轉(zhuǎn)換的,在c+中可用 static_cast()進(jìn)行類型轉(zhuǎn)換。因C+編譯器在編譯檢查一般都能通過;C語言中不能隱式類型轉(zhuǎn)換的,在c+中可以用 reinterpret_ca

42、st() 進(jìn)行強(qiáng)行類型 解釋??偨Y(jié):static_cast()和reinterpret_cast() 基本上把C語言中的 強(qiáng)制類型轉(zhuǎn)換給覆蓋reinterpret_cast()很難保證移植性。4)dynamic_cast(),動(dòng)態(tài)類型轉(zhuǎn)換,安全的基類和子類之間轉(zhuǎn)換;運(yùn)行時(shí)類型檢查5)const_cast(),去除變量的只讀屬性7.3 典型案例7.3.1 static_cast用法和reinterpret_cast用法void main01()double dPi = 3.1415926;/1靜態(tài)的類型轉(zhuǎn)換: 在編譯的時(shí) 進(jìn)行基本類型的轉(zhuǎn)換 能替代c風(fēng)格的類型轉(zhuǎn)換 可以進(jìn)行一部分檢查int nu

43、m1 = static_cast (dPi); /c+的新式的類型轉(zhuǎn)換運(yùn)算符 int num2 = (int)dPi;/c語言的 舊式類型轉(zhuǎn)換 int num3 = dPi;/隱士類型轉(zhuǎn)換cout num1: num1 num2: num2 num3: num3 endl;char *p1 = hello wangbaoming ;int *p2 = NULL;p2 = (int *)p1;/2 基本類型能轉(zhuǎn)換 但是不能轉(zhuǎn)換指針類型/p2 = static_cast (p1); /“static_cast”: 無法從“char *”轉(zhuǎn)換為“int *”/3 可以使用 reinterpret_c

44、ast 進(jìn)行重新解釋 p2 = reinterpret_cast (p1);cout p1 p1 endl;cout p2 p2 endl;/4 一般性的結(jié)論:c語言中 能隱式類型轉(zhuǎn)換的 在c+中可以用 static_cast()進(jìn)行類型轉(zhuǎn)換 /C+編譯器在編譯檢查一般都能通過/c語言中不能隱式類型轉(zhuǎn)換的,在c+中可以用 reinterpret_cast() 進(jìn)行強(qiáng)行類型 解釋 system(pause);return ;7.3.2 dynamic_cast用法和reinterpret_cast用法class Animal public:virtual void cry() = 0; ;cla

45、ss Dog : public Animal public:virtual void cry()cout wangwang endl;void doSwim() cout 我要狗爬 endl; ;class Cat : public Animalpublic:virtual void cry()cout miaomiao endl;void doTree() cout 我要爬樹 endl; ;class Bookpublic:void printP()cout price cry();Dog *pDog = dynamic_cast(base);if (pDog != NULL)pDog-cr

46、y();pDog-doSwim();Cat *pCat = dynamic_cast(base);if (pCat != NULL)pCat-cry();pCat-doTree();void main02()Animal *base = NULL;/1 可以把子類指針賦給 父類指針 但是反過來是不可以的 需要 如下轉(zhuǎn)換/pdog = base; Dog *pDog = static_cast (base);/2 把base轉(zhuǎn)換成其他 非動(dòng)物相關(guān)的 err/Book *book= static_cast (base);/3 reinterpret_cast /可以強(qiáng)制類型轉(zhuǎn)換Book *book

47、2= reinterpret_cast (base);/4 dynamic_cast用法ObjPlay(new Cat();system(pause);7.3.3 const_cast用法/典型用法 把形參的只讀屬性去掉void Opbuf(const char *p)cout p endl;char *p2 = const_cast(p);p20 = b;cout p endl;void main()const char *p1 = 11111111111;char *p2 = 22222222;char *p3 = const_cast(p1);char buf100 = aaaaaaaa

48、aaaa;Opbuf(buf);/要保證指針?biāo)鶊?zhí)行的內(nèi)存空間能修改才行 若不能修改 還是會(huì)引起程序異常/Opbuf(dddddddddddsssssssssssssss);system(pause);7.4 總結(jié)結(jié)論1:程序員要清除的知道: 要轉(zhuǎn)的變量,類型轉(zhuǎn)換前是什么類型,類型轉(zhuǎn)換后是什么類型。轉(zhuǎn)換后有什么后果。結(jié)論2:一般情況下,不建議進(jìn)行類型轉(zhuǎn)換;避免進(jìn)行類型轉(zhuǎn)換。8、異常處理機(jī)制專題前言 1)異常是一種程序控制機(jī)制,與函數(shù)機(jī)制獨(dú)立和互補(bǔ) 函數(shù)是一種以棧結(jié)構(gòu)展開的上下函數(shù)銜接的程序控制系統(tǒng),異常是另一種控制結(jié)構(gòu),它依附于棧結(jié)構(gòu),卻可以同時(shí)設(shè)置多個(gè)異常類型作為網(wǎng)捕條件,從而以類型匹配在棧機(jī)

49、制中跳躍回饋.2)異常設(shè)計(jì)目的: 棧機(jī)制是一種高度節(jié)律性控制機(jī)制,面向?qū)ο缶幊虆s要求對(duì)象之間有方向、有目的的控制傳動(dòng),從一開始,異常就是沖著改變程序控制結(jié)構(gòu),以適應(yīng)面向?qū)ο蟪绦蚋行У毓ぷ鬟@個(gè)主題,而不是僅為了進(jìn)行錯(cuò)誤處理。異常設(shè)計(jì)出來之后,卻發(fā)現(xiàn)在錯(cuò)誤處理方面獲得了最大的好處。8.1 異常處理的基本思想 8.1.1傳統(tǒng)錯(cuò)誤處理機(jī)制通過函數(shù)返回值來處理錯(cuò)誤。8.1.2異常處理的基本思想1)C+的異常處理機(jī)制使得異常的引發(fā)和異常的處理不必在同一個(gè)函數(shù)中,這樣底層的函數(shù)可以著重解決具體問題,而不必過多的考慮異常的處理。上層調(diào)用者可以再適當(dāng)?shù)奈恢迷O(shè)計(jì)對(duì)不同類型異常的處理。2)異常是專門針對(duì)抽象編程中

50、的一系列錯(cuò)誤處理的,C+中不能借助函數(shù)機(jī)制,因?yàn)闂=Y(jié)構(gòu)的本質(zhì)是先進(jìn)后出,依次訪問,無法進(jìn)行跳躍,但錯(cuò)誤處理的特征卻是遇到錯(cuò)誤信息就想要轉(zhuǎn)到若干級(jí)之上進(jìn)行重新嘗試,如圖3)異常超脫于函數(shù)機(jī)制,決定了其對(duì)函數(shù)的跨越式回跳。4)異??缭胶瘮?shù)8.2 C+異常處理的實(shí)現(xiàn)8.2.1異常基本語法1) 若有異常則通過throw操作創(chuàng)建一個(gè)異常對(duì)象并拋擲。2) 將可能拋出異常的程序段嵌在try塊之中??刂仆ㄟ^正常的順序執(zhí)行到達(dá)try語句,然后執(zhí)行try塊內(nèi)的保護(hù)段。3) 如果在保護(hù)段執(zhí)行期間沒有引起異常,那么跟在try塊后的catch子句就不執(zhí)行。程序從try塊后跟隨的最后一個(gè)catch子句后面的語句繼續(xù)執(zhí)行下

51、去。4) catch子句按其在try塊后出現(xiàn)的順序被檢查。匹配的catch子句將捕獲并處理異常(或繼續(xù)拋擲異常)。5) 如果匹配的處理器未找到,則運(yùn)行函數(shù)terminate將被自動(dòng)調(diào)用,其缺省功能是調(diào)用abort終止程序。6)處理不了的異常,可以在catch的最后一個(gè)分支,使用throw語法,向上扔。案例1:被零整除案例int divide(int x, int y )if (y =0)throw x;return x/y;void main41()trycout 8/2 = divide(8, 2) endl;cout 10/0 = divide(10, 0) endl;catch (int

52、 e)cout e is divided by zero! endl;catch(.)cout 未知異常 endl;cout ok endl; system(pause);return ;案例2:class A;void f() if(.) throw A;void g() try f(); catch(B) cout“exception Bn”; int main() g();throw A將穿透函數(shù)f,g和main,抵達(dá)系統(tǒng)的最后一道防線激發(fā)terminate函數(shù)該函數(shù)調(diào)用引起運(yùn)行終止的abort函數(shù)最后一道防線的函數(shù)可以由程序員設(shè)置從而規(guī)定其終止前的行為修改系統(tǒng)默認(rèn)行為:可以通過set_

53、terminate函數(shù)修改捕捉不住異常的默認(rèn)處理器,從而使得發(fā)生捉不住異常時(shí),被自定義函數(shù)處理: void myTerminate()cout“HereIsMyTerminaten”; set_terminate(myTerminate); set_terminate函數(shù)在頭文件exception中聲明,參數(shù)為函數(shù)指針void(*)().案例3:構(gòu)造函數(shù)沒有返回類型,無法通過返回值來報(bào)告運(yùn)行狀態(tài),所以只通過一種非函數(shù)機(jī)制的途徑,即異常機(jī)制,來解決構(gòu)造函數(shù)的出錯(cuò)問題。7)異常機(jī)制與函數(shù)機(jī)制互不干涉,但捕捉的方式是基于類型匹配。捕捉相當(dāng)于函數(shù)返回類型的匹配,而不是函數(shù)參數(shù)的匹配,所以捕捉不用考慮一

54、個(gè)拋擲中的多種數(shù)據(jù)類型匹配問題比如:class A;class B;int main()tryint j = 0; double d = 2.3; char str20 = Hello;couta;switch(a)case 1: throw d; case 2: throw j; case 3: throw str;case 4: throw A(); case 5: throw B();default: coutNo throws here.n; catch(int)coutint exception.n;catch(double)coutdouble exception.n;catch(

55、char*)coutchar* exception.n;catch(A)coutclass A exception.n;catch(B)coutclass B exception.n;coutThats ok.n;system(pause);/=catch代碼塊必須出現(xiàn)在try后,并且在try塊后可以出現(xiàn)多個(gè)catch代碼塊,以捕捉各種不同類型的拋擲。異常機(jī)制是基于這樣的原理:程序運(yùn)行實(shí)質(zhì)上是數(shù)據(jù)實(shí)體在做一些操作,因此發(fā)生異?,F(xiàn)象的地方,一定是某個(gè)實(shí)體出了差錯(cuò),該實(shí)體所對(duì)應(yīng)的數(shù)據(jù)類型便作為拋擲和捕捉的依據(jù)。8)異常捕捉嚴(yán)格按照類型匹配異常捕捉的類型匹配之苛刻程度可以和模板的類型匹配媲美,它不允

56、許相容類型的隱式轉(zhuǎn)換,比如,拋擲char類型用int型就捕捉不到例如下列代碼不會(huì)輸出“int exception.”,從而也不會(huì)輸出“Thats ok.” 因?yàn)槌霈F(xiàn)異常后提示退出int main() try throw H; catch(int) coutint exception.n; couta = a;this-b = b;cout Test 構(gòu)造函數(shù)執(zhí)行 a: a b: b endl;void printT()cout a: a b: b endl;Test()cout Test 析構(gòu)函數(shù)執(zhí)行 a: a b: b endl;private:int a;int b;void myFunc

57、() throw (MyException)Test t1;Test t2;cout 定義了兩個(gè)棧變量,異常拋出后測試棧變量的如何被析構(gòu) endl;throw MyException();void main()/異常被拋出后,從進(jìn)入try塊起,到異常被拋擲前,這期間在棧上的構(gòu)造的所有對(duì)象,/都會(huì)被自動(dòng)析構(gòu)。析構(gòu)的順序與構(gòu)造的順序相反。/這一過程稱為棧的解旋(unwinding)try myFunc();/catch(MyException &e) /這里不能訪問異常對(duì)象catch(MyException ) /這里不能訪問異常對(duì)象cout 接收到MyException類型異常 endl;cat

58、ch(.)cout 未知類型異常 0 ) /如果讀到數(shù)據(jù),則大于0 writelen = fwrite(buf, 1, readlen, fp2);if (readlen != readlen)return 3;fclose(fp1);fclose(fp2);return 0;測試程序void main11()int ret;ret = filecopy01(c:/1.txt,c:/2.txt);if (ret !=0 )switch(ret)case 1:printf(打開源文件時(shí)出錯(cuò)!n);break;case 2:printf(打開目標(biāo)文件時(shí)出錯(cuò)!n);break;case 3:prin

59、tf(拷貝文件時(shí)出錯(cuò)!n);break;default:printf(發(fā)生未知錯(cuò)誤!n);break; throw int類型異常/文件的二進(jìn)制copyvoid filecopy02(char *filename2, char *filename1 )FILE *fp1= NULL, *fp2 = NULL;fp1 = fopen(filename1, rb);if (fp1 = NULL)/return 1;throw 1;fp2 = fopen(filename2, wb);if (fp1 = NULL)/return 2;throw 2;char buf256;int readlen,

60、writelen;while ( (readlen = fread(buf, 1, 256, fp1) 0 ) /如果讀到數(shù)據(jù),則大于0 writelen = fwrite(buf, 1, readlen, fp2);if (readlen != readlen)/return 3;throw 3;fclose(fp1);fclose(fp2);return ; throw字符類型異常/文件的二進(jìn)制copyvoid filecopy03(char *filename2, char *filename1 )FILE *fp1= NULL, *fp2 = NULL;fp1 = fopen(file

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論