版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
C++面向?qū)ο蟪绦蛟O(shè)計(jì)
第一章第1章 C++概述C++ABetterC1.1C++起源和特點(diǎn) 1.1.1 C++的起源
1.1.2 C++的特點(diǎn)1.2C++程序的結(jié)構(gòu)1.2.1
C程序與C++程序比較1.2.2
C++程序結(jié)構(gòu)1.2.3
C++程序的編輯、編譯和運(yùn)行C程序與C++程序比較之一main(){inta,b,sum;/*定義三個(gè)整型變量*/a=123;b=456;
sum=a+b;
printf("sumis%d\n",sum);
}main(){inta,b,sum;
//定義三個(gè)整型變量
a=123;b=456;
sum=a+b;
cout<<sum;
}C程序與C++程序比較之二#include"stdio.h"main(){chara,b,c;a='B';b='O';c='Y';putchar(a);putchar(b);putchar(c);}#include“iostream.h"voidmain(){chara,b,c;a='B';b='O';c='Y';cout<<a<<b<<c;}1.3C++的一些新特性1.3.1單行注釋和新的I/O流1.3.2const修飾符1.3.3內(nèi)聯(lián)函數(shù)1.3.4函數(shù)原型1.3.5帶缺省參數(shù)的函數(shù)1.3.6函數(shù)名重載1.3.7
new和delete運(yùn)算符1.3.8引用(reference)1.3.1單行注釋和新的I/O流//I/Ostream#include<iostream.h>
main(){inti;floatf;chars[80];
cout<<"Enteraninteger,float,andstring:";cin>>i>>f>>s;cout<<"Here'syourdata:"<<i<<''<<f<<endl<<s<<'\n';return0;}單行注釋和新的I/O流(續(xù))cout是預(yù)定義的輸出流對(duì)象,類(lèi)似于C語(yǔ)言中的stdout。<<輸出運(yùn)算符,可用于輸出C++語(yǔ)言中任何基本類(lèi)型的數(shù)據(jù)。cin是預(yù)定義的輸入流對(duì)象,類(lèi)似于C語(yǔ)言中的stdin。<<輸入運(yùn)算符,可用于輸入C++語(yǔ)言中任何基本類(lèi)型的數(shù)據(jù)。(注意:輸入和輸出并不是C++語(yǔ)言的組成部分,它們由流庫(kù)iostream支持。)輸入含有空格的字符串//Usegetline()toreadastringthatcontainsspaces.#include<iostream>#include<fstream>usingnamespacestd;intmain(){charstr[80];cout<<"Enteryourname:";cin.getline(str,79);cout<<str<<'\n';return0;}1.3.2const存取修飾符
對(duì)象A:親愛(ài)的,你千萬(wàn)不能變心?對(duì)象B:放心吧!親愛(ài)的。對(duì)象A:你發(fā)誓!對(duì)象B:不用發(fā)誓,因?yàn)槲沂莄onst!
const對(duì)象B;常量Constants在C中,可以使用#define來(lái)定義符號(hào)常量。C++提供了一種更靈活、更安全的方式來(lái)定義常量,即使用關(guān)鍵字const來(lái)定義符號(hào)常量。常量例子ConstantexamplesconstfloatPI=3.1415926;//PI是一個(gè)常量constintv[]={1,2,3,4};//數(shù)組元素v[i]是常量constintx;//error:noinitializer//定義常量時(shí)應(yīng)初始化,否則出錯(cuò)。voidf(){ model=200;//error v[2]++;//error}值替換valuesubstitution#defineBUFSIZE100constintbufsize=100;Becauseofsubtlebugsthatthepreprocessormightintroduce,youshouldalwaysuseconstinsteadof#definevaluesubstitution.常量const和指針指針?biāo)赶虻膶?duì)象為常量Pointertoconst指針本身為常量constpointerTheconstmodifiesthethingitis“closestto.”指向常量的指針
Pointertoconstconstint*u;//pointertoconstant*u=18;//error:upointstoconstantu=p;//OK常指針constpointerintd=1;int*constw=&d;*w=2;//OKw=p;//error:wisconstconst修飾函數(shù)參數(shù)voidprint_salary(constfloat*salary){ cout<<salary<<’\n’;}const可以阻止參數(shù)被函數(shù)修改const的其他用途
Otherusesofconstreturntypes,classobjectsandmemberfunctionsvolatile存取修飾符修飾符volatile通知編譯器,變量值可能由程序中沒(méi)有顯示說(shuō)明的方式所改變,因此在作編譯優(yōu)化時(shí),不要通過(guò)將該變量放入寄存器來(lái)提高速度。
Volatile原意是:可變的,不穩(wěn)定的externvolatileclock;externconstvolatileclock;1.3.3內(nèi)聯(lián)函數(shù)(內(nèi)嵌函數(shù),
內(nèi)置函數(shù)inlinefunction)在函數(shù)聲明或定義的前面加上關(guān)鍵字“inline”,該函數(shù)就被聲明為內(nèi)聯(lián)函數(shù)。inlineintmax(intx,inty)//max被說(shuō)明為內(nèi)聯(lián)函數(shù){intz;if(x>y)z=x;elsez=y;return(z);}內(nèi)聯(lián)函數(shù)的調(diào)用方法與普通函數(shù)沒(méi)有區(qū)別。類(lèi)中定義的內(nèi)聯(lián)函數(shù)InlinefunctionAnyfunctiondefinedwithinaclassbodyisautomaticallyinline,classDate{ intday,month,year;public: voidinit_date(intdd,intmm,intyy) {day=dd;month=mm;year=yy;}};Hereinit_dateisainlinefunction函數(shù)調(diào)用時(shí)的時(shí)間開(kāi)銷(xiāo)1.函數(shù)調(diào)用時(shí)的時(shí)間開(kāi)銷(xiāo):保護(hù)現(xiàn)場(chǎng),恢復(fù)現(xiàn)場(chǎng)。2.用關(guān)鍵字inline說(shuō)明內(nèi)嵌函數(shù)。編譯器直接用內(nèi)嵌函數(shù)體的編譯代碼插入在函數(shù)調(diào)用語(yǔ)句處,這一過(guò)程稱(chēng)為函數(shù)的嵌入擴(kuò)展。利用內(nèi)嵌函數(shù)減少了調(diào)用普通函數(shù)時(shí)的壓棧和彈棧操作,從而提高程序的運(yùn)行速度。3.內(nèi)嵌函數(shù)比帶參數(shù)的宏的好處。一般情況下,只有較短的函數(shù)才定義為內(nèi)嵌函數(shù)。使用內(nèi)嵌函數(shù)實(shí)際上是一種增加空間開(kāi)銷(xiāo)以減小時(shí)間開(kāi)銷(xiāo)的方法。為什么使用內(nèi)聯(lián)函數(shù)Efficiency
效率
在C程序中,可使用宏macros達(dá)到同樣的目的,但是宏是通過(guò)預(yù)處理來(lái)處理的,不進(jìn)行類(lèi)型檢查,容易造成難以發(fā)現(xiàn)的錯(cuò)誤。宏macros在類(lèi)的內(nèi)部不能使用,宏不能作為類(lèi)的成員。為什么使用內(nèi)聯(lián)函數(shù)(cont.)為了克服宏的上述缺陷,C++引入了內(nèi)聯(lián)函數(shù)。內(nèi)聯(lián)函數(shù)具有高效率,而且:進(jìn)行類(lèi)型檢查,避免出現(xiàn)類(lèi)型不匹配的錯(cuò)誤??梢宰鳛轭?lèi)的成員函數(shù)。Toretaintheefficiencyofthepreprocessormacro,buttoaddthesafetyandclassscopingoftruefunctions,C++hastheinlinefunction.Howdoinlinefunctionswork
編譯器處理內(nèi)聯(lián)函數(shù)的過(guò)程類(lèi)型檢查T(mén)ypechecking(Toassuresafety)將函數(shù)代碼插入到函數(shù)調(diào)用處thensubstitutesthefunctionbodyforthefunctioncall這樣函數(shù)代碼將占據(jù)更所得存儲(chǔ)空間
TheinlinecodedoesoccupyspaceTheshort,smallandfrequentlycalledfunctionsaresuitableforinlinefunctions.1.3.4函數(shù)原型(functionprototype)
什么是函數(shù)原型?描述函數(shù)原型的三大要素:函數(shù)名參數(shù)類(lèi)型函數(shù)返回值類(lèi)型函數(shù)原型的例子:inttranslate(floatx,floaty,floatz);inttranslate(float,float,float);【例1.7】
voidsqr_it();/*functiondeclaration*/intmain(){ intx; x=10; sqr_it(x); printf("Thesquareofxis%d\n",x);return0;}voidsqr_it(int*i){ *i=(*i)*(*i);}運(yùn)行時(shí)出錯(cuò)【例1.7】本例的C程序能夠成功通過(guò)諸如TurboC這樣的C編譯器的檢查,但會(huì)在運(yùn)行階段發(fā)生錯(cuò)誤。該程序運(yùn)行后的結(jié)構(gòu)顯示如下:Thesquareofxis10Nullpointerassignment使用函數(shù)原型執(zhí)行強(qiáng)類(lèi)型檢查【例1.8】voidsqr_it(int*i);//函數(shù)原型
intmain(){ intx; x=10;
sqr_it(x);
cout<<"Thesquareofxis"<<x<<'\n';return0;}voidsqr_it(int*i){ *i=(*i)*(*i);}typemismatch類(lèi)型不匹配函數(shù)原型的作用C++語(yǔ)言是強(qiáng)類(lèi)型化語(yǔ)言,任何函數(shù)在使用以前必須有該函數(shù)的原型說(shuō)明,以便進(jìn)行實(shí)際參數(shù)與形式參數(shù)之間的類(lèi)型匹配檢查。函數(shù)返回值的類(lèi)型和函數(shù)參數(shù)的類(lèi)型、個(gè)數(shù)、次序在函數(shù)聲明,函數(shù)定義和函數(shù)調(diào)用時(shí)必須匹配。C++語(yǔ)言的編譯器執(zhí)行上述檢查能顯著減少很多隱藏的錯(cuò)誤。函數(shù)原型與C語(yǔ)言的函數(shù)類(lèi)型說(shuō)明函數(shù)原型是在C語(yǔ)言的函數(shù)類(lèi)型說(shuō)明(函數(shù)聲明)的基礎(chǔ)上進(jìn)行擴(kuò)充后形成的,它不但說(shuō)明了函數(shù)返回值的類(lèi)型,還要確定函數(shù)參數(shù)的類(lèi)型、個(gè)數(shù)、次序及缺省值。1.3.5帶缺省參數(shù)的函數(shù)例如:以下函數(shù)帶有一個(gè)缺省值為0的參數(shù)。voidmyfunc(doubled=0.0){…}myfunc(198.234);//passanexplicitvaluemyfunc();//letfunctionusedefault缺省參數(shù)的例子voidDrawCircle(intx,inty,intr=10);DrawCircle(50,20);DrawCircle(50,100,30);帶缺省參數(shù)函數(shù)主要由兩個(gè)作用:簡(jiǎn)化編程;有利于程序擴(kuò)充,而不影響原有代碼。1.3.6函數(shù)名重載(overload)兩或兩個(gè)以上的函數(shù)共享同一個(gè)名稱(chēng),就稱(chēng)為函數(shù)名重載。
OverloadedFunctionsMultiplefunctionscanhavethesamenamewithdifferentimplementations.函數(shù)重載簡(jiǎn)化了函數(shù)調(diào)用工作。函數(shù)重載的例子#include<iostream.h>
//Overloadabs()threeways
intabs(intn);longabs(longn);doubleabs(doublen);//prototypeisneccessaryforC++compiler這些都是函數(shù)原型函數(shù)重載的例子main(){cout<<"Absolutevalueof-10:"<<abs(-10)<<"\n";cout<<"Absolutevalueof-10L:"<<abs(-10L)<<"\n";cout<<"Absolutevallueof-10.01:"<<abs(-10.01)<<"\n";
return0;}abs()forints//abs()forintsintabs(intn){cout<<"Inintergerabs()\n";returnn<0?-n:n;}abs()forlongs
//abs()forlongslongabs(longn){cout<<"Inlongabs()\n";returnn<0?-n:n;}abs()fordoubles//abs()fordoublesdoubleabs(doublen){cout<<"Indoubleabs()\n";returnn<0?-n:n;}1.3.7
new和delete運(yùn)算符在C語(yǔ)言中,使用函數(shù)malloc()分配動(dòng)態(tài)內(nèi)存,用函數(shù)free()釋放動(dòng)態(tài)內(nèi)存;在C++語(yǔ)言中,還可以使用運(yùn)算符new分配動(dòng)態(tài)內(nèi)存,用delete釋放動(dòng)態(tài)內(nèi)存。
new和delete的簡(jiǎn)單應(yīng)用//Asimpleexampleofnewanddelete.#include<iostream.h>
main(){int*p;
p=newint;//allocateroomforaninteger
//alwaysmakesurethatallocatesucceededif(!p){cout<<"Allocationerror\n";return1;}Asimpleexampleofnewanddelete(cont)*p=1000;
cout<<"Hereisintegeratp:"<<*p<<"\n";
deletep;//releasememory
return0;}new和delete的優(yōu)點(diǎn)new和delete完成的功能類(lèi)似于malloc()與free(),但它們有幾個(gè)優(yōu)點(diǎn):1)簡(jiǎn)潔性:能自動(dòng)計(jì)算所要分配的內(nèi)存的大?。?)可靠性:編譯時(shí)進(jìn)行類(lèi)型檢查;3)靈活性:new和delete運(yùn)算符可以被重載。注意:用new申請(qǐng)的動(dòng)態(tài)內(nèi)存必須用delete釋放。1.3.8引用(reference)引用是一個(gè)隱含指針,可以看作變量的另一個(gè)名稱(chēng)(別名)。引用有三種使用方法:引用作為函數(shù)參數(shù)(最重要的用法)#include<iostream.h>
voidf(int&n);//declareareferenceparameterusing&
main(){inti=0;
f(i);//Theaddressofvariableiispassed.cout<<"Hereisi'snewvalue:"<<i<<'\n';return0;}引用作為函數(shù)參數(shù)(繼續(xù))//f()nowusesareferenceparametervoidf(int&n){//noticethatno*isneededinthefollowingstatementn=100;//put100intotheargumentusedtocallf()}指針參數(shù)和引用參數(shù)的比較//交換實(shí)際參數(shù)的值voidswap(int*x,int*y){inttemp;
temp=*x;//保存地址x中的值
*x=*y;//putyintox
*y=temp;//putxintoy}
//調(diào)用函數(shù)swap()時(shí)使用變量i和j的地址
swap(&j,&i);//交換實(shí)際參數(shù)的值voidswap(int&x,int&y){inttemp;
temp=x;//保存地址x中的值
x=y;//putyintox
y=temp;//putxintoy}
//調(diào)用函數(shù)swap()時(shí)使用變量i和j的名字
swap(j,i);引用參數(shù)的幾個(gè)好處當(dāng)使用引用參數(shù)的時(shí)候,傳遞的是用作參數(shù)的變量的地址。1)地址被自動(dòng)傳遞;不需要記住傳遞參數(shù)的地址。2)比指針?lè)椒ǜ?jiǎn)練,清晰。3)當(dāng)對(duì)象作為引用被傳遞給函數(shù)的時(shí)候,沒(méi)有進(jìn)行拷貝(復(fù)制)。引用作為函數(shù)的返回值
//Asimpleexampleofafunctionreturnnigareference.#include<iostream.h>int&f();intx;
main(){ f()=100;//f()returntheaddressofx
cout<<x<<"\n";
return0;}引用作為函數(shù)的返回值(繼續(xù))
//Returnanintreference.int&f(){returnx;//returnsareferencetox}獨(dú)立的引用至今沒(méi)有發(fā)現(xiàn)獨(dú)立引用的價(jià)值,在一個(gè)程序中用兩個(gè)名字來(lái)描述同一個(gè)對(duì)象,可能使程序出現(xiàn)混亂。(應(yīng)當(dāng)避免)對(duì)象和類(lèi)屬于同一個(gè)類(lèi)的所有對(duì)象具有某些共性和相似的特征。一個(gè)類(lèi)定義了一組大體上相似的對(duì)象。在面向?qū)ο蟮能浖到y(tǒng)中,對(duì)象是基本的運(yùn)行時(shí)實(shí)體,它既包含數(shù)據(jù),也包括作用于這些數(shù)據(jù)的操作。對(duì)象對(duì)象的組成操作代碼數(shù)據(jù)面向?qū)ο蟮能浖到y(tǒng)對(duì)象4對(duì)象1對(duì)象3對(duì)象2§2.1類(lèi)和對(duì)象的定義2.1.1
C++中對(duì)結(jié)構(gòu)的擴(kuò)展2.1.2
C++中類(lèi)的定義2.1.3
C++類(lèi)中的成員函數(shù)定義2.1.4
C++中對(duì)象的定義和使用2.1.5
C++中類(lèi)的接口與實(shí)現(xiàn)2.1.6類(lèi)聲明與類(lèi)定義2.1.7結(jié)構(gòu)struct與類(lèi)class的比較2.1.1
C++中對(duì)結(jié)構(gòu)的擴(kuò)展C++中的結(jié)構(gòu)不僅可以包含不同類(lèi)型的數(shù)據(jù),而且還可以包含函數(shù)。結(jié)構(gòu)中的數(shù)據(jù)和函數(shù)都是結(jié)構(gòu)的成員,分別稱(chēng)為數(shù)據(jù)成員和函數(shù)成員。在C++中,通常把函數(shù)成員稱(chēng)為成員函數(shù)。C的結(jié)構(gòu)體struct與C++的struct的比較C語(yǔ)言的結(jié)構(gòu)體中數(shù)據(jù)與操作是分離的
在C++語(yǔ)言中將數(shù)據(jù)與操作封裝在一個(gè)結(jié)構(gòu)體中
structStudent{ intnumber; charname[15]; floatscore;};數(shù)據(jù)成員structStudent{intnumber;charname[15];floatscore;voiddisplay()//函數(shù)成員{ cout<<”number:”<<number; cout<<”name:”<<name; cout<<”score:”<<score<<endl;}};/*獨(dú)立函數(shù)display*/voiddisplay(Student*stu){ printf(”number:%d”,stu->number); printf(”name:%s”,stu->name); printf(”score:%f\n”,stu->score);}成員函數(shù)數(shù)據(jù)成員2.1.2
C++中類(lèi)的定義在C++語(yǔ)言中,我們通過(guò)定義新的數(shù)據(jù)類(lèi)型來(lái)實(shí)現(xiàn)類(lèi)。類(lèi)既包含數(shù)據(jù)內(nèi)容又包含對(duì)數(shù)據(jù)的操作,所以類(lèi)是一個(gè)抽象數(shù)據(jù)類(lèi)型。在C++語(yǔ)言中,類(lèi)可被視為一種用戶定義的類(lèi)型。C++的結(jié)構(gòu)體struct與C++的class的比較將數(shù)據(jù)與操作封裝在一個(gè)C++的結(jié)構(gòu)體struct中將數(shù)據(jù)與操作封裝在一個(gè)C++類(lèi)class中數(shù)據(jù)成員structStudent{intnumber;charname[15];floatscore;voiddisplay()//函數(shù)成員{ cout<<”number:”<<number; cout<<”name:”<<name; cout<<”score:”<<score<<endl;}};數(shù)據(jù)成員classStudent{intnumber;charname[15];floatscore;voiddisplay()//函數(shù)成員{ cout<<”number:”<<number; cout<<”name:”<<name; cout<<”score:”<<score<<endl;}};成員函數(shù)數(shù)據(jù)成員一個(gè)復(fù)數(shù)結(jié)構(gòu)的例子structcomplex{doublereal;doubleimage;voidinit(doubler,doublei){real=r;image=i;}doublerealcomplex(){returnreal;}…;};成員函數(shù)數(shù)據(jù)成員私有成員和公有成員在C++中一個(gè)結(jié)構(gòu)的成員通常分為兩類(lèi):私有成員(private)和公有成員(
public)私有成員只能被該結(jié)構(gòu)中的其他成員訪問(wèn)。公有成員既可以被結(jié)構(gòu)內(nèi)的其他成員訪問(wèn),也可以被結(jié)構(gòu)外的成員所訪問(wèn)。C++規(guī)定,在缺省情況下,結(jié)構(gòu)中的成員是公有的。此處所指成員包括數(shù)據(jù)成員和成員函數(shù)。私有成員和公有成員的聲明structcomplex{private:doublereal;doubleimage;public:voidinit(doubler,doublei){real=r;image=i;}doublerealcomplex(
){returnreal;}…;};私有成員公有成員類(lèi)的定義class
類(lèi)名{[private:]
私有數(shù)據(jù)成員和成員函數(shù)public:
公有數(shù)據(jù)成員和成員函數(shù)};//分號(hào)是不能少的//其中,class是聲明類(lèi)的關(guān)鍵字//類(lèi)名是要聲明的類(lèi)的名字類(lèi)中私有成員和公有成員的聲明classcomplex{private:doublereal;doubleimage;public:voidinit(doubler,doublei){real=r;image=i;}doublerealcomplex(){returnreal;}…;};私有成員公有成員定義類(lèi)時(shí)的注意事項(xiàng)private和public可以按任意順序出現(xiàn)具有良好習(xí)慣的程序員會(huì):把所有私有成員和公有成員歸類(lèi)放在一起將私有成員放在公有成員的前面private、public和protected稱(chēng)為訪問(wèn)控制符。數(shù)據(jù)成員可以是任何數(shù)據(jù)類(lèi)型,但不能用auto、register或extern進(jìn)行說(shuō)明。只有在類(lèi)對(duì)象定義之后才能給數(shù)據(jù)成員賦初值。為什么要用類(lèi)代替結(jié)構(gòu)?在缺省情況下,類(lèi)中的成員是私有的private。類(lèi)提供了缺省的安全性。2.1.3
C++類(lèi)中的成員函數(shù)定義C++類(lèi)中的成員函數(shù)描述了對(duì)類(lèi)對(duì)象內(nèi)部數(shù)據(jù)的操作方法,或者說(shuō),描述了對(duì)象的行為,因此我們又將成員函數(shù)稱(chēng)為方法(method)或者服務(wù)(service)?!纠?.2】學(xué)生類(lèi)中成員函數(shù)的定義。成員函數(shù)的定義包含在類(lèi)體中classStudent{private: intnumber; charname[15]; floatscore;public: voidinit(intnumber1,char*name1,floatscore1);
voidmodify(floatscore1) { score=score1; } voidprint();};成員函數(shù)在類(lèi)體外定義voidStudent::init(intnumber1,char*name1,floatscore1){作用域解析運(yùn)算符
number=number1; strcpy(name,name1); score=score1;}voidStudent::print(){ cout<<”number:”<<number<<”name:”<<name<<”score:”<<score<<’\n’;}成員函數(shù)在類(lèi)體內(nèi)外的區(qū)別一般情況下,在類(lèi)體中僅給出成員函數(shù)的原型,而把成員函數(shù)的定義放在類(lèi)體之外實(shí)現(xiàn)。這種將類(lèi)的成員函數(shù)的聲明(declaration)和定義(definition)進(jìn)行分離的方式有很多好處類(lèi)體內(nèi)定義的成員函數(shù)在編譯時(shí)是以內(nèi)聯(lián)函數(shù)處理的,只有那些非常簡(jiǎn)短的函數(shù)才在類(lèi)體中直接定義。2.1.4
C++中對(duì)象的定義和使用在C++語(yǔ)言中,類(lèi)是用戶定義的一種新類(lèi)型,所以可以象聲明普通變量一樣來(lái)建立對(duì)象。在C++語(yǔ)言中,類(lèi)與對(duì)象的關(guān)系就好象整型int和整型變量i之間的關(guān)系一樣。注意:所有類(lèi)對(duì)象都共享它們的成員函數(shù),但是,每一個(gè)對(duì)象都建立并保持自己的數(shù)據(jù)。對(duì)象的數(shù)據(jù)成員,在C++中稱(chēng)為實(shí)例變量。創(chuàng)建對(duì)象的方法之一在定義類(lèi)時(shí)同時(shí)創(chuàng)建對(duì)象,例如:classdate{intmonth,day,year;public:voidsetdate(int,int,int);voidprint();intgetyear();intgetmonth();intgetday();}tt;//同時(shí)創(chuàng)建對(duì)象tt。創(chuàng)建對(duì)象的方法之二在定義類(lèi)后在創(chuàng)建對(duì)象,例如:Datadate1,date2;對(duì)象的使用對(duì)象的性質(zhì)和定義要求將實(shí)例變量隱藏在對(duì)象中,對(duì)它們的訪問(wèn),原則上要通過(guò)其接口——共有的成員函數(shù)來(lái)進(jìn)行。訪問(wèn)對(duì)象的成員時(shí),使用“.”運(yùn)算符:對(duì)象名.成員名稱(chēng);調(diào)用成員函數(shù)是必須指明對(duì)象,事實(shí)上,在C++語(yǔ)言中,我們用OOP術(shù)語(yǔ)發(fā)送消息來(lái)代替“調(diào)用成員函數(shù)”這個(gè)說(shuō)法。2.1.5
C++中類(lèi)的接口與實(shí)現(xiàn)一般把僅含函數(shù)原型的類(lèi)聲明部分稱(chēng)為類(lèi)的接口(interface),例如:classDate{ intday,month,year;public: voidinit(intdd,intmm,intyy);//initialize voidadd_year(intn); //addnyears voidadd_month(intn);//addnmonths voidadd_day(intn); //addndays}C++中類(lèi)的接口與實(shí)現(xiàn)(續(xù))把類(lèi)中成員函數(shù)的定義部分稱(chēng)為類(lèi)的實(shí)現(xiàn)部分(implementation)。例如:voidDate::init(intdd,intmm,intyy){ day=dd; month=mm; year=yy;}inlinevoidDate::add_year(intn){ year+=n;}C++中類(lèi)的接口與實(shí)現(xiàn)(續(xù))C++中的類(lèi)實(shí)現(xiàn)了接口和實(shí)現(xiàn)的分離,這樣只要維持接口不變,實(shí)現(xiàn)部分可以根據(jù)需要不斷改進(jìn),而不影響類(lèi)的使用。類(lèi)的接口部分一般存放在擴(kuò)展名為h的頭文件中,類(lèi)的實(shí)現(xiàn)部分則存放在擴(kuò)展名為cpp的實(shí)現(xiàn)文件中。在cpp文件的開(kāi)頭要用include將h頭文件包含在其中。這個(gè)特征增強(qiáng)了類(lèi)模塊的獨(dú)立性和可重用性(reuse)。設(shè)計(jì)一個(gè)類(lèi)(class)時(shí)的基本原則在設(shè)計(jì)一個(gè)新的類(lèi)(class)類(lèi)型時(shí)的基本原則是將類(lèi)的復(fù)雜的實(shí)現(xiàn)細(xì)節(jié)(例如用來(lái)存儲(chǔ)該類(lèi)對(duì)象的數(shù)據(jù))和正確使用該類(lèi)所需知道的要素(例如訪問(wèn)對(duì)象數(shù)據(jù)的函數(shù))分離開(kāi)來(lái)。這種分離的最好方式就是通過(guò)一個(gè)特定的接口來(lái)使用該類(lèi)的數(shù)據(jù)結(jié)構(gòu)和內(nèi)部處理程序。封裝(encapsulation)在進(jìn)行類(lèi)定義時(shí),我們把需要提供給類(lèi)的用戶的在類(lèi)對(duì)象上執(zhí)行的操作聲明為公用的(public),這樣就形成了類(lèi)的接口。然后按照信息隱藏(informationhiding)的原則來(lái)把類(lèi)的內(nèi)部數(shù)據(jù)表示和實(shí)現(xiàn)細(xì)節(jié)聲明為私有的(private),從而完成了封裝(encapsulation)。封裝性及其好處所謂封裝,在面向?qū)ο蟪绦蛟O(shè)計(jì)中的含義就是包含和隱藏對(duì)象信息,如內(nèi)部數(shù)據(jù)結(jié)構(gòu)和代碼的能力。在C++中封裝是通過(guò)類(lèi)來(lái)實(shí)現(xiàn)的,即將內(nèi)部的數(shù)據(jù)和代碼聲明為私有的,外界不能直接訪問(wèn)。封裝將操作對(duì)象的內(nèi)部復(fù)雜性與應(yīng)用程序的其他部分隔離開(kāi)來(lái)。換句話說(shuō),應(yīng)用類(lèi)對(duì)象的程序員不需要知道類(lèi)內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)就可以使用該類(lèi)。這是面向?qū)ο蟪绦蛟O(shè)計(jì)降低復(fù)雜性的最主要途徑。2.1.6類(lèi)聲明與類(lèi)定義類(lèi)定義包含兩部分:類(lèi)頭和類(lèi)體,類(lèi)體由一對(duì)花括號(hào)包圍起來(lái)。一旦到了類(lèi)體的結(jié)尾,即結(jié)束右邊的花括號(hào),這時(shí)就定義了一個(gè)類(lèi)。一旦定義了一個(gè)類(lèi),則該類(lèi)的所有成員就都是已知的,類(lèi)的大小也是已知的了。類(lèi)聲明由于歷史的原因,類(lèi)的定義(classdefinition)也稱(chēng)為類(lèi)的聲明(declaration)。但是準(zhǔn)確地說(shuō),一旦給出了類(lèi)頭,就聲明了一個(gè)類(lèi)。我們可以聲明一個(gè)類(lèi)但是不定義它。例如:classDate;//Date類(lèi)的聲明這個(gè)聲明向程序引入了一個(gè)名字Date,指示Date為一個(gè)類(lèi)類(lèi)型。類(lèi)聲明(續(xù))如果還沒(méi)有定義類(lèi),那么我們就不能定義這類(lèi)類(lèi)型的對(duì)象但是,我們可以聲明指向這種類(lèi)型對(duì)象的指針或者引用。classDate; //Date類(lèi)的聲明Datepd,&rd;//聲明了指向Date類(lèi)對(duì)象的指針pd和引用rd2.1.7結(jié)構(gòu)struct與類(lèi)class的比較結(jié)構(gòu)和類(lèi)的唯一區(qū)別是:在缺省情況下結(jié)構(gòu)內(nèi)數(shù)據(jù)成員和成員函數(shù)是公有的public,而類(lèi)中的數(shù)據(jù)成員和成員函數(shù)是私有的private。可以說(shuō)C++中的結(jié)構(gòu)是一種特殊的類(lèi)。類(lèi)(或者結(jié)構(gòu))的私有成員只能被該類(lèi)(或者結(jié)構(gòu))的成員函數(shù)訪問(wèn),這是C++實(shí)現(xiàn)封裝的一種方法。§2.2構(gòu)造函數(shù)和析構(gòu)函數(shù)2.2.1構(gòu)造函數(shù)2.2.2析構(gòu)函數(shù)2.2.3重載構(gòu)造函數(shù)2.2.4組合類(lèi)和對(duì)象成員的初始化2.2.1構(gòu)造函數(shù)constructor構(gòu)造函數(shù)是類(lèi)的一種特殊成員函數(shù),用來(lái)為對(duì)象進(jìn)行初始化。構(gòu)造函數(shù)的函數(shù)名與類(lèi)名相同。構(gòu)造函數(shù)的例子1classDate{
intday,month,year;
Date(intdd,intmm,intyy);//constructor};//構(gòu)造函數(shù)名與類(lèi)名相同voidDate::Date(intdd,intmm,intyy){ day=dd; month=mm; year=yy;}用來(lái)為對(duì)象進(jìn)行初始化。構(gòu)造函數(shù)的例子2classStudent{private: intnumber; charname[15]; floatscore;public: Student(intnumber1,char*name1,floatscore1);voidmodify(floatscore1) {score=score1;} voidprint();};構(gòu)造函數(shù)的聲明構(gòu)造函數(shù)的例子2//構(gòu)造函數(shù)的定義Student::Student(intnumber1,char*name1,floatscore1){ number=number1; strcpy(name,name1); score=score1;}構(gòu)造函數(shù)(續(xù))構(gòu)造函數(shù)可以有任一類(lèi)型的參數(shù),但不能具有返回類(lèi)型。當(dāng)定義一個(gè)對(duì)象時(shí),系統(tǒng)自動(dòng)調(diào)用構(gòu)造函數(shù)進(jìn)行初始化。構(gòu)造函數(shù)與其它函數(shù)一樣可以重載也可以有缺省參數(shù)。在對(duì)象生成的時(shí)候自動(dòng)執(zhí)行初始化,這會(huì)消除任何錯(cuò)誤地不執(zhí)行初始化的可能。這是C++面向?qū)ο蟪绦蛟O(shè)計(jì)幫助減少?gòu)?fù)雜性的另一途徑。有缺省參數(shù)的構(gòu)造函數(shù)classcomplex{private:doublereal;doubleimage;public:voidcomplex(doubler=0.0,doublei=0.0){real=r;image=i;}doublerealcomplex(){returnreal;}…;};缺省參數(shù)2.2.2析構(gòu)函數(shù)析構(gòu)函數(shù)的作用與構(gòu)造函數(shù)正好相反,當(dāng)對(duì)象被刪除時(shí),利用析構(gòu)函數(shù)進(jìn)行一些善后處理。一般情況下析構(gòu)函數(shù)執(zhí)行構(gòu)造函數(shù)的逆操作,例如可以利用析構(gòu)函數(shù)來(lái)釋放構(gòu)造函數(shù)所動(dòng)態(tài)申請(qǐng)的內(nèi)存空間。析構(gòu)函數(shù)的名稱(chēng)與其類(lèi)名稱(chēng)相同,并在名稱(chēng)的前邊加~(鍵盤(pán)上的波浪符號(hào))符號(hào)。一個(gè)類(lèi)中只能有一個(gè)析構(gòu)函數(shù)。(不能重載)析構(gòu)函數(shù)不允許有返回值,并且析構(gòu)函數(shù)不允許帶參數(shù)。參見(jiàn)【例2.7】。構(gòu)造函數(shù)和析構(gòu)函數(shù)的例子//構(gòu)造函數(shù)的定義Student::Student(intnumber1,char*name1,floatscore1){ number=number1; name=newchar[strlen(name1)+1];//申請(qǐng)動(dòng)態(tài)內(nèi)存單元
strcpy(name,name1); score=score1;}//析構(gòu)函數(shù)的定義Student::~Student(){
delete[]name;//釋放動(dòng)態(tài)內(nèi)存單元}2.2.3重載構(gòu)造函數(shù)構(gòu)造函數(shù)與其它函數(shù)一樣可以重載也可以有缺省參數(shù)。要重載類(lèi)的構(gòu)造函數(shù),只需要在類(lèi)中聲明構(gòu)造函數(shù)的不同函數(shù)原型并且定義相關(guān)的函數(shù)體。重載構(gòu)造函數(shù)主要有三個(gè)原因
1.為了獲得靈活性:提供給用戶多種初始化對(duì)象的選項(xiàng)。2.為了支持?jǐn)?shù)組:要聲明一個(gè)類(lèi)的對(duì)象數(shù)組則該類(lèi)應(yīng)具有一個(gè)不帶參數(shù)的構(gòu)造函數(shù)。3.為了自定義復(fù)制構(gòu)造函數(shù),將對(duì)象進(jìn)行準(zhǔn)確的復(fù)制(拷貝):參見(jiàn)第5章堆與復(fù)制構(gòu)造函數(shù)。
重載構(gòu)造函數(shù)例一classDate{ intd,m,y;public://... Date(int,int,int);//day,month,year Date(int,int);//day,month,today’syear Date(int);//day,today’smonthandyear Date();//defaultDate:today Date(constchar*);//dateinstringrepresentation};為了獲得靈活性:提供給用戶多種初始化對(duì)象的選項(xiàng)2.2.4組合類(lèi)和對(duì)象成員的初始化當(dāng)一個(gè)類(lèi)的對(duì)象作為一個(gè)類(lèi)的成員時(shí),稱(chēng)為該類(lèi)的對(duì)象成員。使用對(duì)象成員著重要注意的問(wèn)題是一個(gè)類(lèi)的內(nèi)部對(duì)象的初始化問(wèn)題。類(lèi)的對(duì)象成員初始化#include"iostream.h"classinner_class{ intx;public: inner_class(intz){x=z;} voidwrite(){cout<<x<<endl;}};類(lèi)的對(duì)象成員初始化(續(xù))classouter_class{ inty; inner_classx; inner_classr;public: outer_class(intz); voidwrite(){cout<<y<<endl;} voidwrite_inner_x() {x.inner_class::write();} voidwrite_inner_r() {r.inner_class::write();}};注意:outer_class類(lèi)對(duì)象在通過(guò)構(gòu)造函數(shù)進(jìn)行初始化的同時(shí),也要對(duì)其成員對(duì)象進(jìn)行初始化。類(lèi)的對(duì)象成員初始化(續(xù))outer_class::outer_class(intz):x(20),r(-36){y=z;}main(){ outer_classobj(10); obj.write_inner_x(); obj.write_inner_r(); obj.write(); return0;}初始化參數(shù)傳遞鏈初始化和撤銷(xiāo)的順序先里后外:先調(diào)用對(duì)象成員的構(gòu)造函數(shù),再調(diào)用外圍類(lèi)的成員函數(shù)。雖然對(duì)象成員調(diào)用它們類(lèi)的構(gòu)造函數(shù),但此時(shí)寫(xiě)的是對(duì)象的名字,而不是類(lèi)名。先外后里:當(dāng)撤銷(xiāo)一個(gè)包含對(duì)象成員的對(duì)象時(shí),該對(duì)象的析構(gòu)函數(shù)將先執(zhí)行,然后再調(diào)用對(duì)象成員的析構(gòu)函數(shù)。【例2.9】對(duì)象成員的初始化。//注意:在定義Student類(lèi)的構(gòu)造函數(shù)時(shí),必須綴上對(duì)象成員的名字birthdayStudent::Student(intnumber1,char*name1,floatscore1,intd1,intm1,inty1):birthday(d1,m1,y1)//對(duì)象成員birthday的初始化{ number=number1; strcpy(name,name1); score=score1;}2.3類(lèi)與const軟件工程的歷史經(jīng)驗(yàn)表明,程序內(nèi)部相當(dāng)多的隱蔽錯(cuò)誤是由于無(wú)意中修改了某些數(shù)據(jù)的值造成的。對(duì)數(shù)據(jù)進(jìn)行保護(hù)是減少程序中的錯(cuò)誤,提高軟件的可靠性的有效途徑之一。在C++中還廣泛使用const關(guān)鍵字,用來(lái)實(shí)現(xiàn)對(duì)共享數(shù)據(jù)的保護(hù),提高軟件的安全性。2.3.1常成員函數(shù)
ConstantMemberFunctionsclassDate{ intd,m,y;public: intday()const{returnd;} intmonth()const{returnm;} intyear()const; //...};使用const關(guān)鍵字說(shuō)明的函數(shù)常成員函數(shù)不更新對(duì)象的數(shù)據(jù)成員。(只讀函數(shù))常成員函數(shù)(續(xù))inlineintDate::year()const//正確{ returny;}inlineintDate::year()//錯(cuò)誤{ returny;}const是函數(shù)類(lèi)型的一個(gè)組成部分,因此在實(shí)現(xiàn)部分也要帶const關(guān)鍵字。遺漏了const關(guān)鍵字常成員函數(shù)(續(xù))inlineintDate::year()const{ returny++;}將出現(xiàn)編譯錯(cuò)誤信息:企圖在常成員函數(shù)中修改對(duì)象的數(shù)據(jù)成員。2.3.2常對(duì)象constantobject常對(duì)象是指對(duì)象常量,定義格式如下:<類(lèi)名>const<對(duì)象名>或者
const<類(lèi)名><對(duì)象名>
例如:constDatecd;常對(duì)象constantobject(續(xù))必須對(duì)常對(duì)象進(jìn)行初始化,而且不能被更新。常對(duì)象只能調(diào)用它的常成員函數(shù)。普通的對(duì)象既可以調(diào)用它的常成員函數(shù),也可以調(diào)用普通成員函數(shù)。請(qǐng)看下面的例子:常對(duì)象constantobject(續(xù))voidf(Date&d,constDate&cd){ inti=d.year();//ok d.add_year(1);//ok intj=cd.year();//ok cd.add_year(1);//錯(cuò)誤}常對(duì)象不能調(diào)用它的普通成員函數(shù)3.1類(lèi)與對(duì)象3.1.1對(duì)象3.1.2類(lèi)3.1.3對(duì)象與類(lèi)的關(guān)系對(duì)象的廣義定義什么是對(duì)象(object)?現(xiàn)實(shí)世界中的任何一個(gè)事物都可以看成是一個(gè)對(duì)象。自然的實(shí)體:一個(gè)人,一輛汽車(chē),一個(gè)教師邏輯結(jié)構(gòu):一個(gè)銀行帳號(hào),一個(gè)學(xué)生的學(xué)籍檔案,客戶通信錄對(duì)象的特性對(duì)象是人們要研究的任何事物,其特性是:1、每一個(gè)對(duì)象必須有一個(gè)名字以區(qū)別于其它對(duì)象;2、用屬性(或叫狀態(tài))來(lái)描述它的某些特征;3、有一組操作,每一個(gè)操作決定對(duì)象的一種行為。//這是關(guān)于對(duì)象的廣義定義面向?qū)ο蟮南到y(tǒng)中的對(duì)象對(duì)象是基本的運(yùn)行時(shí)實(shí)體,它既包含數(shù)據(jù)(屬性),也包括作用與數(shù)據(jù)的操作(行為)。一個(gè)對(duì)象把屬性和行為封裝成一個(gè)整體。對(duì)象是數(shù)據(jù)和對(duì)數(shù)據(jù)的操作的結(jié)合體。從程序設(shè)計(jì)者來(lái)看,對(duì)象是一個(gè)程序模塊;從用戶來(lái)看,對(duì)象為他們提供了所希望的行為。類(lèi)的例子人類(lèi)水果類(lèi)魚(yú)類(lèi)“類(lèi)”是對(duì)一組具有共同屬性特征和行為特征的對(duì)象的抽象。OOP中類(lèi)的例子classStudent{ intnumber; char*name; floatscore;public:
Student(intnumber1,char*name1,floatscore1); ~Student(); voidmodify(floatscore1); voidprint();};屬性操作什么是類(lèi)(class)?在C++語(yǔ)言中,我們通過(guò)定義新的數(shù)據(jù)類(lèi)型來(lái)構(gòu)成類(lèi)。在新的數(shù)據(jù)類(lèi)型中,既包含數(shù)據(jù)內(nèi)容又包含對(duì)數(shù)據(jù)的操作。一個(gè)類(lèi)所包含的方法和數(shù)據(jù)描述一組對(duì)象的共同行為和屬性。什么是類(lèi)(class)?一個(gè)類(lèi)定義了一個(gè)大體上相似的對(duì)象。把一組對(duì)象的共同特性加以抽象并存儲(chǔ)在一個(gè)類(lèi)中的能力,是面向?qū)ο蠹夹g(shù)最重要的一點(diǎn)。對(duì)象與類(lèi)的關(guān)系類(lèi)是對(duì)一組性質(zhì)相同的對(duì)象的描述,是對(duì)一組數(shù)據(jù)和方法的封裝。對(duì)象則是類(lèi)的具體化,是類(lèi)的實(shí)例??梢赃@樣定義對(duì)象:對(duì)象是類(lèi)的一個(gè)實(shí)例,包括了數(shù)據(jù)和過(guò)程。3.2消息和方法3.2.1消息3.2.2方法消息Message消息是要求某個(gè)對(duì)象執(zhí)行其中某個(gè)功能操作的規(guī)格說(shuō)明。OOP中的一條消息由消息選擇器(“消息操作”或“消息名”)及若干個(gè)參數(shù)和接受消息的對(duì)象三部分組成,例如:student1.modify(score1);消息的例子接受消息的對(duì)象參數(shù)↓↓student1.modify(score1);↑
消息名發(fā)送消息與函數(shù)調(diào)用的比較1) 函數(shù)調(diào)用可以帶或不帶參量,但消息至少帶一個(gè)參量(對(duì)象名或?qū)ο笾羔槪凰该鹘邮茉撓⒌膶?duì)象。消息選擇器則告訴對(duì)響應(yīng)作些什么。2) 消息名(消息選擇器或消息操作)類(lèi)似于函數(shù)名,但二者之間的本質(zhì)差別在于:函數(shù)名僅代表一段可執(zhí)行的代碼,而消息名的具體功能的實(shí)現(xiàn)取決于所接受消息的對(duì)象。發(fā)送消息與函數(shù)調(diào)用的比較(續(xù))3) 函數(shù)調(diào)用是過(guò)程式(面向過(guò)程)的即“如何做(Howtodo)”,而消息則是通知式(面向?qū)ο螅┑?,即告訴對(duì)象“做什么(Whattodo)”,具體“如何做(Howtodo)”由對(duì)象根據(jù)接受到的消息自行確定。lst.sort();其中,lst代表一個(gè)鏈表對(duì)象,sort是表示排序的消息名。方法(method)“方法”對(duì)應(yīng)于對(duì)象的行為(能力),即它是實(shí)現(xiàn)對(duì)象所具有的功能操作的代碼段。在C++程序中,方法即是類(lèi)中定義的成員函數(shù),它是該類(lèi)對(duì)象所能執(zhí)行的操作的算法實(shí)現(xiàn)。通常每個(gè)類(lèi)中包含多個(gè)方法(即C++的成員函數(shù)),每個(gè)方法由方法名(函數(shù)名+參數(shù)表)和說(shuō)明該成員函數(shù)的算法實(shí)現(xiàn)的一段代碼所組成。方法的例子voidStudent::print(){ cout<<”number:”<<number<<”name:”<<name<<”score:”<<score<<’\n’;}方法是與對(duì)象相連決定怎么做的操作執(zhí)行代碼,所以方法是實(shí)現(xiàn)每條消息具體功能的手段。3.3什么是面向?qū)ο蟪绦蛟O(shè)計(jì)3.3.1結(jié)構(gòu)化程序設(shè)計(jì)方法3.3.2面向?qū)ο蟪绦蛟O(shè)計(jì)方法表3.1程序設(shè)計(jì)方法的發(fā)展過(guò)程1957~1972:面向過(guò)程的程序設(shè)計(jì)1968~1990:面向過(guò)程的結(jié)構(gòu)化程序設(shè)計(jì)1984~今:面向?qū)ο蟮某绦蛟O(shè)計(jì)結(jié)構(gòu)化程序設(shè)計(jì)的基本思想按功能劃分模塊,分而治之。分解系統(tǒng)時(shí)按照自頂向下的順序,逐步求精。設(shè)計(jì)時(shí)使各模塊間的關(guān)系盡可能簡(jiǎn)單,功能上相對(duì)獨(dú)立,從而可單獨(dú)驗(yàn)證模塊的正確性。結(jié)構(gòu)化程序的組成
主控模塊功能模塊1功能模塊7功能模塊2功能模塊3功能模塊6功能模塊5功能模塊4圖3.3結(jié)構(gòu)化程序的組成結(jié)構(gòu)化程序設(shè)計(jì)方法的基本特點(diǎn)把數(shù)據(jù)結(jié)構(gòu)和處理數(shù)據(jù)的操作過(guò)程分離為相互獨(dú)立的實(shí)體。用數(shù)據(jù)表達(dá)實(shí)際問(wèn)題中的信息;程序代碼則實(shí)現(xiàn)用于處理加工這些數(shù)據(jù)的算法。簡(jiǎn)而言之,就是數(shù)據(jù)和操作代碼分離。
數(shù)據(jù)和操作代碼分離產(chǎn)生的問(wèn)題給程序員增加了負(fù)擔(dān):必須確保數(shù)據(jù)和代碼匹配。當(dāng)數(shù)據(jù)結(jié)構(gòu)改變時(shí),所有相關(guān)的處理過(guò)程都要進(jìn)行相應(yīng)的修改。可維護(hù)性低。即使要對(duì)不同的數(shù)據(jù)格式(結(jié)構(gòu)和類(lèi)型)作同樣的處理計(jì)算,也必須編寫(xiě)不同的程序??芍赜眯圆缓?。面向?qū)ο蟪绦蛟O(shè)計(jì)用面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言中的對(duì)象和類(lèi)直接模擬現(xiàn)實(shí)世界中的對(duì)象,將問(wèn)題空間直接映射到軟件空間。從而設(shè)計(jì)出盡可能直接、自然地表示問(wèn)題求解方法的軟件。面向?qū)ο蟮倪@種思維方式符合人類(lèi)的自然思維習(xí)慣,使我們能夠在程序中自然地描述現(xiàn)實(shí)世界的實(shí)體和問(wèn)題,增強(qiáng)了程序代碼的可讀性,有利于控制軟件的復(fù)雜性。模塊化將一個(gè)復(fù)雜的大規(guī)模軟件系統(tǒng)劃分成幾個(gè)規(guī)模較小、相對(duì)簡(jiǎn)單的模塊,即分而治之。面向?qū)ο蟪绦蛟O(shè)計(jì)方法是按對(duì)象來(lái)劃分。面向?qū)ο蟮能浖到y(tǒng)由對(duì)象組成,對(duì)象之間通過(guò)消息傳遞互相聯(lián)系,如圖3.4所示。面向?qū)ο蟮能浖到y(tǒng)的組成
對(duì)象1對(duì)象2對(duì)象3對(duì)象4圖中箭頭表示對(duì)象之間的消息傳遞對(duì)象作為程序模塊面向?qū)ο蟮能浖到y(tǒng)中每一個(gè)模塊都是高度獨(dú)立的對(duì)象,而對(duì)象是比功能模塊粒度更大的模塊。對(duì)象是由數(shù)據(jù)和對(duì)數(shù)據(jù)的操作(代碼)形成的一個(gè)整體。面向?qū)ο蟪绦蛟O(shè)計(jì)采用封裝的辦法,使對(duì)象的內(nèi)部實(shí)現(xiàn)與外界隔離,實(shí)現(xiàn)了信息隱藏,從而提供了更理想的模塊化機(jī)制,顯著地減少了程序模塊間的相互干擾和依賴性。
數(shù)據(jù)抽象技術(shù)
將數(shù)據(jù)和對(duì)數(shù)據(jù)的操作封裝在一起,作為一個(gè)相互依存、不可分割的整體——對(duì)象來(lái)處理,它采用數(shù)據(jù)抽象和信息隱藏技術(shù)。它將具有相同特征的對(duì)象抽象成一個(gè)新的數(shù)據(jù)類(lèi)型——類(lèi),并且考慮不同對(duì)象之間的聯(lián)系和對(duì)象類(lèi)的重用性3.4數(shù)據(jù)抽象3.4.1什么是抽象?3.4.2數(shù)據(jù)抽象和抽象數(shù)據(jù)類(lèi)型抽象性的例子classstudent{ intnumber; char*name; floatscore;public: student(intnumber1,char*name1,floatscore1); ~student(); voidmodify(floatscore1); voidprint();};抽象是有選擇地忽略。抽象性(Abstraction)抽象是對(duì)復(fù)雜的現(xiàn)實(shí)世界的簡(jiǎn)明的表示。抽象強(qiáng)調(diào)了我們所關(guān)心的(感興趣)的信息,而將我們不關(guān)心的其他信息忽略。名家之言E.Dijkstra:“設(shè)計(jì)并實(shí)現(xiàn)一個(gè)大規(guī)模的軟件的中心問(wèn)題是怎樣減小復(fù)雜度,一個(gè)途徑就是通過(guò)抽象”。BjarneStroustrup說(shuō):“在C++語(yǔ)言中,我一直在努力提高程序設(shè)計(jì)的抽象層次”。抽象數(shù)據(jù)類(lèi)型一個(gè)值集和作用在值集上的操作集
C++語(yǔ)言中的一個(gè)類(lèi)就是一個(gè)抽象數(shù)據(jù)類(lèi)型每個(gè)抽象數(shù)據(jù)類(lèi)型自成一個(gè)模塊,模塊的接口和內(nèi)部實(shí)現(xiàn)分離開(kāi)來(lái),使用模塊的應(yīng)用程序員只需要知道如何使用該模塊,而不必知道模塊內(nèi)部是如何實(shí)現(xiàn)的,也就是說(shuō),可以忽略模塊內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)。
3.5封裝性和信息隱藏所謂封裝(encapsulation),就是包含和隱藏對(duì)象信息,如內(nèi)部數(shù)據(jù)結(jié)構(gòu)和代碼的能力。在面向?qū)ο蟮某绦蛑校ㄟ^(guò)創(chuàng)建對(duì)象將代碼和數(shù)據(jù)捆綁在一起,并且在對(duì)象中包含了所有必需的代碼和數(shù)據(jù)。對(duì)象是支持封裝的元素。一個(gè)程序中的對(duì)象把現(xiàn)實(shí)世界中的實(shí)體的屬性和行為封裝成一個(gè)整體。信息隱藏(informationhiding)
封裝的好處封裝性降低了程序設(shè)計(jì)的復(fù)雜度。
封裝將操作對(duì)象的內(nèi)部復(fù)雜性與應(yīng)用程序的其他部分隔離開(kāi)來(lái)。應(yīng)用程序員只需要通過(guò)對(duì)象的接口來(lái)操作對(duì)象完成特定的任務(wù),而不需要知道對(duì)象內(nèi)部復(fù)雜的細(xì)節(jié)。
封裝的好處(續(xù))提高了代碼的安全性和可靠性;通過(guò)類(lèi)實(shí)現(xiàn)封裝,集中和統(tǒng)一了對(duì)類(lèi)中數(shù)據(jù)成員的所有操作,從而可避免因分散操作造成的錯(cuò)誤。能有效提到程序模塊的獨(dú)立性、可重用性和可維護(hù)性;只要類(lèi)的接口(即類(lèi)的共有部分)保持不變,類(lèi)的結(jié)構(gòu)部分的任何變化(包括數(shù)據(jù)結(jié)構(gòu)和算法)都不會(huì)對(duì)使用該類(lèi)的源程序有所影響,源程序可以不做任何修改。面向?qū)ο蟪绦蛟O(shè)計(jì)的主要特征抽象性封裝性繼承性多態(tài)性3.6繼承性與軟件重用面向?qū)ο蟪绦蛟O(shè)計(jì)的第二個(gè)主要特征就是繼承性,繼承的目的就是為了重用(reuse)。
繼承,就是在一個(gè)已有的類(lèi)的基礎(chǔ)上創(chuàng)建一個(gè)新類(lèi)
,這個(gè)新類(lèi)獲得了已有類(lèi)的數(shù)據(jù)和操作代碼,并且新類(lèi)可以增加新的數(shù)據(jù)和操作代碼。
繼承與派生問(wèn)題舉例派生類(lèi)的概念在已有類(lèi)的基礎(chǔ)上新增自己的特性而產(chǎn)生新類(lèi)的過(guò)程稱(chēng)為派生。被繼承的已有類(lèi)稱(chēng)為基類(lèi)(或父類(lèi))。派生出的新類(lèi)稱(chēng)為派生類(lèi)(或子類(lèi))。參見(jiàn)圖3.5類(lèi)的繼承
繼承與派生的目的繼承的目的:實(shí)現(xiàn)代碼重用。派生的目的:當(dāng)新的問(wèn)題出現(xiàn),原有程序無(wú)法解決(或不能完全解決)時(shí),需要對(duì)原有程序進(jìn)行改造。C++中類(lèi)的繼承層次自然地表達(dá)了人們分析問(wèn)題時(shí)所用的分類(lèi)結(jié)構(gòu)。大大改善了軟件系統(tǒng)的可理解性和可維護(hù)性。
繼承的好處(1)繼承性很好地實(shí)現(xiàn)了代碼的重用。(2)能改進(jìn)軟件系統(tǒng)的可維護(hù)性。(3)繼承性使已有的程序庫(kù)具有清晰的層次結(jié)構(gòu)關(guān)系。3.7多態(tài)性廣義多態(tài)性:自然語(yǔ)言中的多態(tài)性;面向?qū)ο蟪绦蛟O(shè)計(jì)中的多態(tài)性什么是多態(tài)性?(廣義)polymorphism,“manyforms”:即多種形態(tài)在自然語(yǔ)言中,多態(tài)性即是“一詞多義”;更準(zhǔn)確地說(shuō),多態(tài)性是指相同的動(dòng)詞作用到不同類(lèi)型的對(duì)象上,例如:
駕駛摩托車(chē) 駕駛汽車(chē) 駕駛飛機(jī) 駕駛輪船駕駛宇宙飛船什么是多態(tài)性?(OOP)當(dāng)不同對(duì)象接受到相同的消息產(chǎn)生不同的動(dòng)作,這種性質(zhì)稱(chēng)為多態(tài)性。通俗地說(shuō),多態(tài)性是指用一個(gè)名字定義不同的函數(shù),這些函數(shù)執(zhí)行不同但又類(lèi)似的操作,即用同樣的接口訪問(wèn)功能不同的函數(shù),從而實(shí)現(xiàn)“一個(gè)接口,多種方法”。多態(tài)性的例子在C語(yǔ)言中,由于不支持多態(tài),求絕對(duì)值的動(dòng)作要求三個(gè)不同的函數(shù)名字:
abs(),labs(),fabs()分別用來(lái)求整數(shù),長(zhǎng)整數(shù)、浮點(diǎn)數(shù)的絕對(duì)值。在C++語(yǔ)言中,由于支持多態(tài),求絕對(duì)值的動(dòng)作可以只用一個(gè)函數(shù)名:abs()應(yīng)用多態(tài)性的好處多態(tài)應(yīng)用于OOP的目的是允許用一個(gè)名字來(lái)指定動(dòng)作的一般類(lèi)(即邏輯上相似的動(dòng)作)。從而帶來(lái)以下的好處:提高了處理問(wèn)題的抽象級(jí)別;降低了程序設(shè)計(jì)時(shí)的復(fù)雜性;增強(qiáng)了軟件的靈活性。面向?qū)ο蟪绦蛟O(shè)計(jì)的優(yōu)越性重用性:有利于軟件生產(chǎn)率的提高;符合人類(lèi)的自然思維習(xí)慣,能夠自然地描述現(xiàn)實(shí)世界的實(shí)體和問(wèn)題:有利于控制軟件的復(fù)雜性;更好的模塊化,便于多人分工和合作開(kāi)發(fā)軟件;編寫(xiě)的代碼有更好的可維護(hù)性;3.8面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言3.8.1對(duì)象程序設(shè)計(jì)語(yǔ)言的發(fā)展概況3.8.2幾種典型的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言幾種典型的OOPLSmalltalkC++JavaC#
4.1對(duì)象數(shù)組(Objectarrays)定義: 類(lèi)名數(shù)組名[元素個(gè)數(shù)];例如:StudentaSA[10];//一個(gè)學(xué)生類(lèi)對(duì)象數(shù)組通過(guò)下標(biāo)訪問(wèn)方法: 數(shù)組名[下標(biāo)].成員名;例如:aSA[j].print();對(duì)象數(shù)組初始化數(shù)組中每一個(gè)元素對(duì)象被創(chuàng)建時(shí),系統(tǒng)都會(huì)調(diào)用構(gòu)造函數(shù)類(lèi)初始化該對(duì)象。通過(guò)初始化列表賦值。例:
LocationA[2]={Location(1,2),Location(3,4)};如果沒(méi)有為數(shù)組元素指定顯式初始值,數(shù)組元素使用缺省值初始化(調(diào)用缺省構(gòu)造函數(shù))。當(dāng)數(shù)組中每一個(gè)對(duì)象被刪除時(shí),系統(tǒng)都要調(diào)用一次析構(gòu)函數(shù)。數(shù)組元素所屬類(lèi)的構(gòu)造函數(shù)沒(méi)有自定義構(gòu)造函數(shù)時(shí),則采用缺省構(gòu)造函數(shù)。各元素對(duì)象的初值要求為相同的值時(shí),可以定義出具有缺省形參值的構(gòu)造函數(shù)。各元素對(duì)象的初值要求為不同的值時(shí),需要定義帶形參(無(wú)缺省值)的構(gòu)造函數(shù)。如果需要定義動(dòng)態(tài)數(shù)組,需要一個(gè)無(wú)參構(gòu)造函數(shù)。對(duì)象數(shù)組例子#include<iostream.h>classsamp{inta,b;public:samp(intn,intm){a=n;b=m;}intget_a(){returna;}intget_b(){returnb;}};對(duì)象數(shù)組例子(續(xù))main(){sampob[4][2]={samp(1,2),samp(3,4),samp(5,6),samp(7,8),samp(9,10),samp(11,12),samp(13,14),samp(15,16),};inti;對(duì)象數(shù)組例子(續(xù))
for(i=0;i<4;i++){cout<<ob[i][0].get_a();cout<<ob[i][0].get_b()<<"\n";cout<<ob[i][1].get_a();cout<<ob[i][1].get_b()<<"\n";}cout<<"\n";return0;}4.2指向?qū)ο蟮闹羔樋梢远x指向?qū)ο蟮闹羔?,在運(yùn)用對(duì)象的指針的時(shí)候,對(duì)象的成員將用箭頭運(yùn)算符(→)而不是點(diǎn)運(yùn)算符(.)引用。對(duì)象的指針?biāo)惴ㄅc其它數(shù)據(jù)類(lèi)型的指針?biāo)惴ㄏ嗤核慌c對(duì)象相聯(lián)系的處理。例如:當(dāng)對(duì)象指針增加的時(shí)候,它指向下一個(gè)對(duì)象;當(dāng)對(duì)象指針減少的時(shí)候,它指向前一個(gè)對(duì)象。對(duì)象指針的用法
intmain(){
Circlec1(3),*pc;//pc為指向圓形Circle類(lèi)對(duì)象的指針
pc=&c1; //將對(duì)象c1的地址賦給對(duì)象指針pc,使其指向圓形對(duì)象c1
cout<<c1.GetArea()<<endl; //通過(guò)對(duì)象名訪問(wèn)對(duì)象的方法
cout<<pc->GetArea()<<endl;//通過(guò)對(duì)象指針訪問(wèn)對(duì)象的方法
return0;}對(duì)象指針與對(duì)象數(shù)組#include"student.h"intmain(){… Student*sp=aSA; //給指針賦初值
for(inti=0;i<4;i++,sp++)sp->print();//指針加1后,指向下一個(gè)對(duì)象
sp=sp-3; //指針減3后,指針向前移動(dòng)三個(gè)對(duì)象
sp->modify(87); sp->print(); return0;}4.3this指針對(duì)象是由數(shù)據(jù)和操作構(gòu)成的一個(gè)整體,即使同一類(lèi)的不同對(duì)象的操作也是相互獨(dú)立的,各占不同的內(nèi)存空間。但是,在C++實(shí)現(xiàn)中,這種處理方案太浪費(fèi)內(nèi)存空間。同類(lèi)的對(duì)象能否共享該類(lèi)成員函數(shù)的同一個(gè)實(shí)例呢?myBirthday.set(31,12,1997);nationalDay.set(1.10,1949);voidDate::Set(intD,intM,inty){day=D;month=M;year=Y;}那么,此時(shí)計(jì)算機(jī)怎么能區(qū)分該函數(shù)是作用在哪個(gè)對(duì)象上呢?解決方案C++在編譯時(shí),自動(dòng)在每個(gè)成員函數(shù)中的第一個(gè)參數(shù)位置增加:
X*constthis;
當(dāng)對(duì)象調(diào)用該函數(shù)時(shí),編譯器自動(dòng)將該對(duì)象的指針作為實(shí)參傳遞給相應(yīng)的函數(shù),這樣就可解決上述問(wèn)題:voidDate::Set(Date*constthis,intD,intM,intY){this->day=D;this->month=M;this->year=Y;}
注:程序員不能將this指針的說(shuō)明寫(xiě)在函數(shù)中C的結(jié)構(gòu)體struct與C++的struct的比較C語(yǔ)言的結(jié)構(gòu)體中數(shù)據(jù)與操作是分離的
在C++語(yǔ)言中將數(shù)據(jù)與操作封裝在一個(gè)結(jié)構(gòu)體中
structStudent{ intnumber; charname[15]; floatscore;};數(shù)據(jù)成員structStudent{intnumber;charname[15];floatscore;voiddisplay(Student*this)//函數(shù)成員{ cout<<”number:”<<this->number; cout<<”name:”<<this->name; cout<<”score:”<<this->score<<endl;}};/*獨(dú)立函數(shù)display*/voiddisplay(Student*stu){ printf(”number:%d”,stu->number); printf(”name:%s”,stu->name); printf(”score:%f\n”,stu->score);}數(shù)據(jù)成員this指針this指針是由C++編譯器自動(dòng)產(chǎn)生而使用的一個(gè)隱含指針,類(lèi)成員函數(shù)使用該指針來(lái)存取對(duì)象的數(shù)據(jù)成員。
定義同一類(lèi)的多個(gè)對(duì)象時(shí),每個(gè)對(duì)象擁有自己的數(shù)據(jù)成員但它們共用一份成員函數(shù),當(dāng)成員函數(shù)存取對(duì)象的數(shù)據(jù)時(shí)它們使用this指針,通過(guò)this指針指向不同對(duì)象來(lái)決定使用哪一個(gè)對(duì)象的數(shù)據(jù)成員。this指針是如何在“幕后”工作?例如complex類(lèi)中的init函數(shù):voidinit(doubler,doublei){real=r;image=i;}C++編譯器在編譯這個(gè)函數(shù)時(shí)自動(dòng)插入this指針:voidinit(complex*this,doubler,doublei){this->real=r;this->image=i;}this指針的顯式使用this指針是系統(tǒng)的一個(gè)內(nèi)部指針,通常以隱式方式使用,但也可以為程序員所使用,例如,當(dāng)運(yùn)算符重載和建立鏈表時(shí)this指針顯得十分重要。參見(jiàn)雙向鏈表This指針的顯式用法顯式地使用this指針,還可以使C++的編譯器將同名的參數(shù)與數(shù)據(jù)成員區(qū)分開(kāi)來(lái):voidDate::Set(intday,intmonth,intyear){this->day=day;this->month=month;this->year=year;}4.4對(duì)象的賦值如果兩個(gè)對(duì)象屬于同一種類(lèi)型,那么我們可以將其中的一個(gè)對(duì)象的值(屬性值)賦給另一個(gè)對(duì)象。在默認(rèn)情況下,當(dāng)將一個(gè)對(duì)象賦值給另一個(gè)對(duì)象時(shí),第一個(gè)對(duì)象的數(shù)據(jù)將被按位復(fù)制到第二個(gè)對(duì)象中。對(duì)象賦值的例子【例4.4】
intmain(){Rectanglerect1(10,20),rect2(0,0);
cout<<"r
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年城市公共服務(wù)設(shè)施建設(shè)項(xiàng)目合同
- 2024年度影視作品授權(quán)使用合同
- 2024年度貨物采購(gòu)協(xié)議
- 2024年國(guó)際快遞公司服務(wù)協(xié)議
- 2024年度建筑材料采購(gòu)合同
- 2024年度供應(yīng)鏈管理服務(wù)合同標(biāo)的說(shuō)明
- 04版7月:股權(quán)激勵(lì)計(jì)劃協(xié)議
- 信息技術(shù)2.0培訓(xùn)項(xiàng)目個(gè)人研修計(jì)劃
- 七夕節(jié)品牌宣傳文案(55句)
- 2024年建筑工程施工合同詳解
- 光伏消防演練方案及流程
- 2024年秋季新西師大版一年級(jí)上冊(cè)數(shù)學(xué)課件 第二單元 0~9的加減法 猜數(shù)字
- 2023-2024學(xué)年北京市通州區(qū)七年級(jí)(上)期中數(shù)學(xué)試卷【含解析】
- 英美文學(xué)講練 English Literature EXERCISES
- 武漢理工大學(xué)博士后年度業(yè)務(wù)考核表
- “雙減”小學(xué)語(yǔ)文四年級(jí)上冊(cè)單元作業(yè)設(shè)計(jì)案例
- 高低壓電力系統(tǒng)預(yù)試驗(yàn)及維保服務(wù)方案
- 濾波電路課件講解
- 2024-2030年國(guó)內(nèi)鋁合金鎖行業(yè)市場(chǎng)發(fā)展分析及發(fā)展前景與投資機(jī)會(huì)研究報(bào)告
- 冶金企業(yè)的冶煉生產(chǎn)計(jì)劃三篇
- 課題論文:推動(dòng)發(fā)展培育新質(zhì)生產(chǎn)力
評(píng)論
0/150
提交評(píng)論