《C++面向?qū)ο蟪绦蛟O(shè)計導(dǎo)論》-從抽象到編程 課件 張力生 第7、8章 模板與模板庫、課程成績管理應(yīng)用案例_第1頁
《C++面向?qū)ο蟪绦蛟O(shè)計導(dǎo)論》-從抽象到編程 課件 張力生 第7、8章 模板與模板庫、課程成績管理應(yīng)用案例_第2頁
《C++面向?qū)ο蟪绦蛟O(shè)計導(dǎo)論》-從抽象到編程 課件 張力生 第7、8章 模板與模板庫、課程成績管理應(yīng)用案例_第3頁
《C++面向?qū)ο蟪绦蛟O(shè)計導(dǎo)論》-從抽象到編程 課件 張力生 第7、8章 模板與模板庫、課程成績管理應(yīng)用案例_第4頁
《C++面向?qū)ο蟪绦蛟O(shè)計導(dǎo)論》-從抽象到編程 課件 張力生 第7、8章 模板與模板庫、課程成績管理應(yīng)用案例_第5頁
已閱讀5頁,還剩79頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

模板與模板庫《C++面向?qū)ο蟪绦蛟O(shè)計導(dǎo)論:從抽象到編程》章節(jié)的內(nèi)容目錄7.1類模板8.2教師錄入成績的視圖7.1.4類模板的代碼重用7.1.2類模板的聲明7.1.1類模板的概念7.1.3類模板的具體化和實例化7.1.5類模板的繼承和關(guān)聯(lián)本節(jié)學習目標能夠運用類、關(guān)聯(lián)等知識解釋類模板和模板類的概念能夠運用預(yù)編譯等知識解釋類模板的具體化能夠運用類的實例化等知識解釋模板類的實例化能夠使用C++聲明、實現(xiàn)類模板,定義、使用其對象7.1.1類模板的概念類模板是對類的抽象,用于描述多個類的共同屬性和行為。復(fù)數(shù)在數(shù)學中表示為:a+bi其中,a、b為實數(shù),并規(guī)定i2等于-1。classComplex_float{ floata; floatb;};classComplex_double{ doublea; doubleb;};template<classT>classComplex{

Ta;

Tb;};classComplex<float>{ floata; floatb;};classComplex<double>{ doublea; doubleb;};抽象具體化7.1.2類模板的聲明使用類模板不僅可以描述類的屬性,還以描述其他成員函數(shù)。例如,類模板Complex中聲明構(gòu)造函數(shù)、析構(gòu)函數(shù),并重載賦值、加法和減法運算。模板參數(shù)T,當成數(shù)據(jù)類型使用【例7.1】類模板Complex//ComplexApp.cpp#include<iostream>#include<iomanip>usingnamespacestd;

template<classT>classComplex//聲明一個類模板,有一個模板參數(shù)T{public: Complex(){}; Complex(Tx,Ty)//其中T為模板參數(shù),作為數(shù)據(jù)類型使用 { a=x; b=y; }; ~Complex(){}; Complex(constComplex&complex){ a=complex.a; b=complex.b; }; Complex&operator=(constComplex&complex) { a=complex.a; b=complex.b; return*this; }; Complexoperator+(constComplex&complex)const { Complexrt(a,b); rt.a+=complex.a; rt.b+=complex.b; returnrt; }; Complexoperator-(constComplex&complex)const { Complexrt(a,b); rt.a-=complex.a; rt.b-=complex.b; returnrt; }; voiddiplay()const { cout<<setprecision(10)<<a<<"+"<<b<<"i"; }private:

Ta;//其中T為模板參數(shù),作為數(shù)據(jù)類型使用

Tb;};模板參數(shù)T,當成數(shù)據(jù)類型使用【例7.1】類模板Complexvoidf1(){ floatx=3.0;

Complex<float>

c,a(1.2,2+1/x),b(3.4,5); c=a+b; cout<<endl<<"float:"; a.diplay(); cout<<"+"; b.diplay(); cout<<"="; c.diplay();}voidf2(){ doublex=3.0;

Complex<double>

c,a(1.2,2+1/x),b(3.4,5); c=a+b; cout<<endl<<"double:"; a.diplay(); cout<<"+"; b.diplay(); cout<<"="; c.diplay();}voidmain(){ f1(); f2(); f3();}voidf3(){ intx=3;

Complex<int>

c,a(1.2,2+1/x),b(3.4,5); c=a+b; cout<<endl<<"int:"; a.diplay(); cout<<"+"; b.diplay(); cout<<"="; c.diplay();}具體化出三個模板類:Complex<float>,Complex<double>,Complex<int>7.1.3具體化和實例化編譯器編譯類模板的工作非常復(fù)雜,但可簡單分為具體化和實例化兩個過程。類模板到模板類的變換過程稱為類模板的具體化(classtemplatespecialization),有時也將變換得到的模板類稱為類模板的具體類(specializationofclasstemplate)。模板類到對象的變換過程稱為類模板的實例化(classtemplateinstantiation)。例如,編譯語句Complex<float>c,a(1.2,2+1/x),b(3.4,5)過程中,先將類模板Complex具體化為模板類Complex<float>,然后再將模板類Complex<float>編譯為可執(zhí)行代碼,最后創(chuàng)建對象c、a、b。【例7.2】模板類Complex<float>的代碼(具體化)classComplex<float> //聲明Complex的一個模板類{public: Complex<float>(){}; Complex<float>(floatx,floaty){ a=x; //使用float上的賦值運算 b=y; }; ~Complex<float>(){}; Complex<float>(constComplex<float>&complex){ a=complex.a; b=complex.b; }; Complex<float>&operator=(constComplex<float>&complex) { a=complex.a; b=complex.b; return*this; }; Complex<float>operator+(constComplex<float>&complex)const { Complex<float>rt(a,b); //創(chuàng)建模板類的對象 rt.a+=complex.a; //使用float上的加法運算 rt.b+=complex.b; returnrt; }; Complex<float>operator-(constComplex<float>&complex)const { Complex<float>rt(a,b); rt.a-=complex.a; //使用float上的減法運算 rt.b-=complex.b; returnrt; }; voiddiplay()const { cout<<setprecision(10)<<a<<"+"<<b<<"i"; }private:

floata; floatb;};將模板類Complex代碼中的模板參數(shù)T替換為數(shù)據(jù)類型float,也使用模板類的名稱Complex<float>替換了代碼中的類模板名Complex。實例化:Complex<float>模板類及其對象Complex<float>(floatx,floaty){ a=x;//使用float上的賦值運算 b=y;};7.1.4類模板的代碼重用//Complex_h#pragma

once#if!defined(__template_Complex_h)#define

__template_Complex_h

#include

<iostream>#include

<iomanip>using

namespacestd;

template<class

T>class

Complex{public: Complex(); Complex(Tx,Ty); ~Complex(); Complex(const

Complex&complex);

Complex&operator=(const

Complex&complex);

Complexoperator+(const

Complex&complex)const;

Complexoperator-(const

Complex&complex)const;

voiddiplay()const;private:

Ta;

Tb;};template<class

T>Complex<T>::Complex(){};template<class

T>Complex<T>::Complex(T

x,T

y){ a=x; b=y;};template<class

T>Complex<T>::~Complex(){};template<class

T>Complex<T>::Complex(const

Complex<T>&complex){ a=complex.a; b=complex.b;};template<class

T>Complex<T>Complex<T>::operator+(const

Complex<T>&complex)const{

Complex<T>rt(a,b); rt.a+=complex.a; rt.b+=complex.b;

returnrt;};template<class

T>Complex<T>&Complex<T>::operator=(const

Complex<T>&complex){ a=complex.a; b=complex.b;

return*this;};template<class

T>Complex<T>Complex<T>::operator-(const

Complex<T>&complex)const{

Complex<T>rt(a,b); rt.a-=complex.a; rt.b-=complex.b;

returnrt;};template<class

T>void

Complex<T>::diplay()const{ cout<<setprecision(10)<<a<<"+"<<b<<"i";}typedef

Complex<float>Complexfloat;#endif確保只引入#include一次(聲明和實現(xiàn)代碼)【例7.3-4】類模板Complex的聲明和實現(xiàn)代碼【例7.5】使用類模板Complex//Complexapp1.cpp#include"Complex.h"http://引入類模板

#include<iostream>usingnamespacestd;voidmain(){

Complex<float>c,a(1.2,2.3),b(3.4,5 c=a-b

)

;//編譯器自動生成一個模板類Complex<float> a.diplay(); cout<<"+"; b.diplay(); cout<<"="; c.diplay();}使用多源文件結(jié)構(gòu)時,可不可能為Complex生成多個目標代碼?7.1.5類模板的繼承和關(guān)聯(lián)描述其模板類之間的繼承和關(guān)聯(lián)【例7.6】類模板中聲明繼承和關(guān)聯(lián)//template.h#include

<iostream>using

namespacestd;

template<class

T>class

Parent{public: Parent(T

d){parentData=d;};

voiddisplay(){cout<<"Parent:"<<parentData<<endl;}protected:

TparentData;};template<class

T>class

classTemplate{public: classTemplate(T

d){data=d;}

voiddisplay(){cout<<"classTemplate:"<<data<<endl;}protected:

Tdata;};template<class

T1,class

T2>class

Child

:public

Parent<T1>{public: Child(T1

d1,T2

d2,float

d3):Parent<T1>(d1),attributeT(d2),attribute(d3) {}; voiddisplay(){ cout<<"Child:"<<endl;

Parent<T1>::display(); attributeT.display(); attribute.display(); }protected:

classTemplate<T2>attributeT;

classTemplate<float>attribute;};//templateApp.cpp#include

"template.h"

intmain(){

Child<char,int>c('a',2,5.5); c.display();

return0;}將模板類當成類來使用!!練習寫出模板類Complex<double>的聲明代碼和實現(xiàn)代碼。Complex<double>d(1.2,3.4),使用對象圖描述對象d的邏輯結(jié)構(gòu)參考7.1.3類模板的具體化和實例化中的方法總結(jié)及進一步學習思維:對類進行再次抽象(抽象思維)設(shè)計:類模板及其關(guān)聯(lián)、繼承,模板類參數(shù)、模板類編碼:類模板的聲明和實現(xiàn),其對象的定義和使用調(diào)試:類模板的具體化、實例化7.2使用模板編程的方法進一步學習第7章模板與模板庫7.2使用模板編程的方法8.2教師錄入成績的視圖7.2.2冒泡排序模板7.2.1動態(tài)數(shù)組類模板7.2.3編程中需要注意的問題學習目標能夠使用類模板存儲和管理多個數(shù)據(jù)(容器)能夠使用函數(shù)模板描述通用算法7.2.1動態(tài)數(shù)組類模板使用myArray<Wheel>管理wheel1.聲明類模板myArray【例7.7】類模板myArray//myArray.htemplate<class

T>class

myArray{public: myArray(int

n){ pElement=new

T[n];

if(pElement) size=n;

else size=0; } ~myArray(){

if(pElement)

delete[]pElement; } myArray(myArray&oldMyArray){

for(inti=0;i<size;i++)

//使用賦值運算拷貝數(shù)組元素中的數(shù)據(jù) pElement[i]=oldMyArray[i]; }

T&operator[](int

index){

returnpElement[index]; };private:

T*pElement;

intsize;};將“模板參數(shù)”當成“數(shù)據(jù)類型”來使用2.使用類模板myArray//CarApp.cpp#include

"myArray.h"

//引入動態(tài)數(shù)組的類模板

#include

<iostream>using

namespacestd;class

Motor{public: Motor(int

sn,float

fPower){ serialNumber=sn; power=fPower; }

voidprint(){ cout<<serialNumber<<","<<power; }private:

intserialNumber;//產(chǎn)品序列號

floatpower;//發(fā)動機的排量};

class

Wheel{public: Wheel(){};//創(chuàng)建車輪的數(shù)組時會調(diào)用這個無參的構(gòu)造函數(shù) Wheel(int

sn,float

fSize){ serialNumber=sn; size=fSize; }

voidprint(){ cout<<serialNumber<<","<<size; }

Wheel&operator=(Wheel&t){//拷貝構(gòu)造函數(shù)中使用賦值運算 serialNumber=t.serialNumber; size=t.size;

return*this; }private:

intserialNumber;//產(chǎn)品序列號

floatsize;//車輪大小};class

Car{public:

Car():wheel(4){}//通知模板類myArray<Wheel>為4個車輪分配內(nèi)存

Motor&set(Motor&depart){

Motor&rt=*motor; motor=&depart;

returnrt; }

Wheel&set(Wheel&depart,int

position){

Wheel&rt=wheel[position]; wheel[position]=depart;

returnrt; }

voidprint(){ cout<<"汽車\t發(fā)動機:"; motor->print(); cout<<"\t\t車輪:";

for(inti=0;i<4;i++){ wheel[i].print(); cout<<"|"; } cout<<endl; }private:

myArray<Wheel>wheel;

Motor*motor;};【例7.8】

使用模板類myArray<Wheel>存儲和管理4個車輪對象將“模板類”當成“類”來使用voidmain(){

Carcar;

//裝配發(fā)動機

Motor*m=new

Motor(123,1.6);//創(chuàng)建一個發(fā)動機對象 car.set(*m);

//裝配4個車輪

for(inti=0;i<4;i++){

Wheelw(201+i,10);//創(chuàng)建了車輪對象,執(zhí)行4次,創(chuàng)建了4個 car.set(w,i); } car.print();

deletem;//創(chuàng)建發(fā)動機對象}使用對象圖描述car的內(nèi)部結(jié)構(gòu)3.容器的概念容器類:數(shù)組、棧、隊列、樹等很多經(jīng)典的數(shù)據(jù)結(jié)構(gòu)容器:用于存儲和管理對象7.2.2冒泡排序模板容器類用于存儲和管理代表客觀事物的對象,相當于集合,對象相當于集合中的元素,可以進行查找、排序等各種操作。1.函數(shù)模板的概念2.聲明冒泡排序函數(shù)模板3.復(fù)數(shù)排序1.函數(shù)模板的概念#include

"complex.h"

//交換兩個對象值的函數(shù)模板template<class

T>voidmySwap(T&a,T&b){

Ttemp=a;

a=b;

b=temp;}voidmain(){

inta=1,b=2; mySwap(a,b);//調(diào)用函數(shù)的原型mySwap(int,int)

Complex<int>c(1,2),d(3,4);//

調(diào)用函數(shù)的原型mySwap(Complex<int>,Complex<int>) mySwap(c,d);}具體化為兩個函數(shù):mySwap(int,int)mySwap(Complex<int>,Complex<int>)2.聲明冒泡排序函數(shù)模板#include

<iostream>using

namespacestd;

template<class

T>boolascending(T&a,T&b){

return(a>b?true:false);}template<class

T1,class

T2>

voidbubble(T1&a,int

size,bool(*fp)(T2&a,T2&b))//冒泡排序{

inti;

T2temp;

for(intpass=1;pass<size;pass++){//共比較size-1輪

for(i=0;i<size-pass;i++){//一輪比較

if(fp(a[i],a[i+1])){ temp=a[i];

a[i]=a[i+1];

a[i+1]=temp; } } }}template<class

T1,class

T2>voidprint(T1&array,int

len){

for(inti=0;i<len;i++) cout<<(T2)array[i]<<","; cout<<endl;}【例7.10】

冒泡排序函數(shù)模板3.復(fù)數(shù)排序//Complex.htemplate<class

T>boolComplex<T>::operator>(constComplex<T>&complex)const{

boolrt;

//比較兩個復(fù)數(shù)的模,但沒有開平方

if(a*a+b*b>complex.a*complex.a+complex.b*complex.b) rt=true;

else rt=false;

returnrt;};template<class

T>ostream&operator<<(ostream&out,Complex<T>&x){

x.display(out);

return

out;}【例7.11】

重載類模板Complex的比較和插入運算【例7.12】復(fù)數(shù)排序#include

"complex.h"#include

"myArray.h"#include

"sort.h"#include

<iostream>using

namespacestd;typedefComplex<int>ComplexlSpecialization;voidmain(){

floatarray[]={55,2.5,6,4,32.8,12,9,73.5,26,37};

intlen=sizeof(array)/sizeof(int);//元素個數(shù)

cout<<endl<<"****數(shù)排序****"<<endl;

myArray<float>array1(len);

//初始化數(shù)組元素

for(inti=0;i<len;i++){ array1[i]=array[i]; }

print<myArray<float>,float>(array1,len); cout<<"升序排序"<<endl;

bubble<myArray<float>,float>(array1,len,ascending);//按升序排序 print<myArray<float>,float>(array1,len);

cout<<endl<<"****復(fù)數(shù)排序****"<<endl; myArray<ComplexlSpecialization>array2(len);

//初始化數(shù)組元素 array2[0]=ComplexlSpecialization(0,array[1]);

for(inti=1;i<len;i++){ array2[i]=ComplexlSpecialization(array[i-1],array[i]); } print<myArray<ComplexlSpecialization>,ComplexlSpecialization>(array2,len); cout<<"升序排序"<<endl;

bubble<myArray<ComplexlSpecialization>,ComplexlSpecialization>(array2,len,ascending); print<myArray<ComplexlSpecialization>,ComplexlSpecialization>(array2,len);}7.2.3編程中需要注意的問題(1)設(shè)計和實現(xiàn)一個類時,應(yīng)通過構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù)賦予其對象管理內(nèi)部數(shù)據(jù)的能力,重載賦值運算,賦予其對象參與計算的基礎(chǔ)能力,重載插入和提取運算,以方便使用流類進行輸入輸出。(2)對象參與計算的能力,是代碼重用的前提,也是代碼質(zhì)量的基礎(chǔ)(3)類越基礎(chǔ)越底層,其對象參與計算的能力就應(yīng)越強。上機調(diào)試中發(fā)現(xiàn)問題,解決問題練習設(shè)計使用模板類myArray<Wheel>存儲和管理4個車輪對象,并完善所有的類,最終設(shè)計出類圖。編碼綜合運用前面所學編程知識,根據(jù)類圖進行編碼。在IDE中直接編碼,如出現(xiàn)錯誤,回去完善設(shè)計調(diào)試出現(xiàn)錯誤,回去完善設(shè)計,重新編碼。不斷迭代,直到調(diào)試通過。圖3.19汽車及其部件參照7.2中的方法,針對右圖重新做設(shè)計,并編碼實現(xiàn)。總結(jié)及進一步學習分析設(shè)計:使用模板管理數(shù)據(jù)(容器類),描述通用算法編碼調(diào)試:綜合運用,要求高、難度大7.3標準模板庫(STL)進一步學習學習:使用模板描述數(shù)據(jù)結(jié)構(gòu)和算法的基本原理和編程方法章節(jié)的內(nèi)容目錄標準模板庫和持久化對象8.2教師錄入成績的視圖7.4.2以文本方式持久化對象7.3.2流類(Stream)

7.3.1容器類(Container)7.4.1輸入輸出對象中的數(shù)據(jù)7.4.3以二進制方式持久化對象學習目標能夠查閱標準模板庫的說明文檔(MSDN)能夠讀懂常用數(shù)據(jù)結(jié)構(gòu)和算法的說明,讀懂其示例代碼能夠使用IO流實現(xiàn)對象的持久化7.3標準模板庫(STL)C++

標準中定義了一個模板庫,稱為標準模板庫

(StandardTemplateLibrary,簡稱為STL)。標準模板庫提供了常用的數(shù)據(jù)結(jié)構(gòu)和算法,功能豐富,但也涉及到大量編程的基礎(chǔ)知識和基本原理,以及海量的技術(shù)細節(jié),編程過程中務(wù)必學會查閱標準模板庫的參考手冊,并養(yǎng)成隨時查閱的習慣。7.3.1容器類(Container)STL中,將常用的數(shù)據(jù)結(jié)構(gòu)封裝為類模板,程序員依據(jù)具體情況選擇適當?shù)念惸0宥x容器,用于管理程序中的對象名稱數(shù)據(jù)結(jié)構(gòu)頭文件字符串(string)字符數(shù)組,C++風格的字符串string向量(vector)動態(tài)大小的數(shù)組vector雙向隊列(deque)雙向隊列deque棧(stack)棧stack隊列(queue)隊列queue鏈表(list)鏈表list集合(set)二叉樹,無重復(fù)元素set多重集合(multiset)二叉樹,允許重復(fù)元素set映射(map)二叉樹,無重復(fù)鍵值的鍵值樹map多重映射(multimap)二叉樹,允許有重復(fù)鍵值的鍵值樹map7.3.1容器類(Container)字符串string是C++風格的字符串,封裝了一個動態(tài)字符數(shù)組。string中封裝了插入insert、刪除delete、拷貝copy、替換replace、查找find等操作。向量vector封裝了一個動態(tài)數(shù)組,不僅能夠動態(tài)地創(chuàng)建一個數(shù)組,還提供了增加元素和減少元素的功能。

示例代碼參考教材。7.3.2流類(Stream)C++標準模板庫中,針對標準輸入輸出設(shè)備、文件、字符串等不同場景提供了多個流類。類ios是基類,派生出輸入流istream和輸出流ostream,針對文件再派生出輸入文件流ifstream和輸出文件流ofstream,針對字符串派生出輸入串流istringstream和輸入串流ostringstream。

示例代碼參考教材。7.3.2流類(Stream)C++標準模板庫中,針對標準輸入輸出設(shè)備、文件、字符串等不同場景提供了多個流類。類ios是基類,派生出輸入流istream和輸出流ostream,針對文件再派生出輸入文件流ifstream和輸出文件流ofstream,針對字符串派生出輸入串流istringstream和輸出串流ostringstream。

示例代碼參考教材。查閱標準模板庫的文檔(MSDN)查閱隨機文檔(MSDN)讀懂詳細說明(可借助字典軟件)讀懂示例代碼(針對性非常強)7.4應(yīng)用舉例:持久化對象持久化對象指將對象中的內(nèi)存數(shù)據(jù)轉(zhuǎn)儲到能長久存儲數(shù)據(jù)的硬件設(shè)備或邏輯設(shè)備上,如轉(zhuǎn)儲到硬盤中的文件,另一臺計算機上的數(shù)據(jù)庫,甚至采用云存儲方式存儲到云端。7.4.1輸入輸出對象中的數(shù)據(jù)7.4.2以文本方式持久化對象7.4.3以二進制方式持久化對象7.4.1輸入輸出對象中的數(shù)據(jù)istream&Student::input(istream&in){

if(!(in>>studentID))//判斷條件等價于in.fail() cerr<<"讀入學號錯誤!"<<endl;

else

if(!(in>>name)) cerr<<"讀入姓名錯誤!"<<endl;

return

in;}ostream&Student::output(ostream&out){

out<<studentID<<"\t"<<name<<endl;

return

out;}ostream&operator<<(ostream&out,StudentBase&x){

return

x.output(out);}istream&operator>>(istream&in,StudentBase&x){

return

x.input(in);}重載了基類StudentBase的插入和提取兩個運算。Student中重寫了input和output兩個純函數(shù)?!纠?.25】使用文本流輸入輸出對象中的數(shù)據(jù)7.4.2以文本方式持久化對象//app.cpp#include<string>#include<iostream>#include

<fstream>#include<vector>using

namespacestd;#include

"Student.h"

intreadData(vector<Student>&st,constchar*pFile="student.txt"){

ifstreamifs(pFile);

Students;

intcnt=0;

while(ifs>>s){//判斷條件等價于!ofs.fail()

st.push_back(s); cnt++; } ifs.close();//關(guān)閉文件

returncnt;}intwriteData(vector<Student>&st,char*pFile="student.txt"){

ofstreamofs(pFile,ios::out|ios_base::binary);

intcnt=0;

for(vector<Student>::iteratorit=st.begin();it!=st.end();it++){

if(!(ofs<<*it))

break; cnt++; } ofs.close();//關(guān)閉文件

returncnt;}【例7.26】

按照文本方式持久化Student對象通過重載插入和提取兩個運算,實現(xiàn)了輸入輸出對象中的數(shù)據(jù),然后就可以使用輸入輸出流持久化學生對象,逐個讀取,增加到向量,存儲到文件7.4.2以文本方式持久化對象voidmain(){

vector<Student>st;

intcnt=0; cnt=readData(st); cout<<"讀取了"<<cnt<<"條數(shù)據(jù)"<<endl;

cnt=writeData(st,"student.dat"); cout<<"保存了"<<cnt<<"條數(shù)據(jù)"<<endl;}讀入學號錯誤!讀取了33條數(shù)據(jù)保存了33條數(shù)據(jù)

【例7.26】輸出結(jié)果

7.4.3以二進制方式持久化對象//Student.h/*********************StudentB************************/class

StudentB:publicStudentBase{public: StudentB(); StudentB(constStudent&old);

virtualistream&input(istream&in);

virtualostream&output(ostream&out);};

//Student.cpp/*********************StudentB************************/StudentB::StudentB(){};StudentB::StudentB(constStudent&old):StudentBase(old){};

istream&StudentB::input(istream&in){

charlen=0; //用一個字節(jié)存儲姓名的長度

char*pBuf=NULL;

in.read((char*)&studentID,sizeofstudentID);

if(in)

in.read((char*)&len,sizeoflen);//讀取1個字節(jié)

if(in) pBuf=new

char[len];

if(pBuf)

in.read(pBuf,len);

if(in) name=string(pBuf);

return

in;}ostream&StudentB::output(ostream&out){

charlen=name.length()+1;//用一個字節(jié)存儲姓名的長度

out.write((char*)&studentID,sizeofstudentID);

if(out)

out.write((char*)&len,sizeoflen);//寫入1個字節(jié)

if(out)

out.write((char*)name.data(),len);

return

out;}【例7.27】使用二進制流輸入輸出對象中的數(shù)據(jù)StudentB中重寫了input和output兩個純函數(shù)。7.4.3以二進制方式持久化對象//app.cpp#include<string>#include

<fstream>#include<iostream>#include<vector>using

namespacestd;

#include

"Student.h"template<classT>intreadData(vector<T>&st,char*pFile="student.txt"){

ifstreamifs(pFile);

Ts;

intcnt=0;

while(ifs>>s){//判斷條件等價于!ofs.fail()

st.push_back(s); cnt++; } ifs.close();//關(guān)閉文件

returncnt;

}template<classT>intwriteData(vector<T>&st,char*pFile="student.txt"){

ofstreamofs(pFile,ios::out|ios_base::binary);

intcnt=0;

for(vector<T>::iteratorit=st.begin();it!=st.end();it++){

if(!(ofs<<*it))

break; cnt++; } ofs.close();//關(guān)閉文件

returncnt;}改寫為函數(shù)模板7.4.3以二進制方式持久化對象voidmain(){

vector<Student>st; intcnt=0; cnt=readData(st); cout<<"從文本文件讀取了"<<cnt<<"條數(shù)據(jù)"<<endl;

vector<StudentB>stb; for(vector<Student>::iteratorit=st.begin();it!=st.end();it++) stb.push_back(StudentB(*it));

cnt=writeData(stb,"studentb.dat"); cout<<"保存了"<<cnt<<"條數(shù)據(jù)到二進制文件"<<endl;

cnt=readData(stb,"studentb.dat"); cout<<"從二進制文件讀取了"<<cnt<<"條數(shù)據(jù)"<<endl;}每個類負責自己數(shù)據(jù)的輸入輸入。練習

調(diào)試通過【例7.27】中的代碼跟蹤程序的執(zhí)行過程,并使用時序圖描述。運用模板、多態(tài)、重載等前面所知識向其他人講解執(zhí)行的流程要求對照時序圖和代碼講解針對【例7.27】

使用二進制流輸入輸出對象中的數(shù)據(jù)本節(jié)總結(jié)及進一步學習自學能力:找到并能讀懂STL的文檔(MSDN)分析設(shè)計:容器、流,持久化技術(shù)編碼調(diào)試:讀懂文檔中的示例代碼并能改寫第8章課程成績管理應(yīng)用案例進一步學習THANKS《C++面向?qū)ο蟪绦蛟O(shè)計導(dǎo)論:從抽象到編程》第7章課程成績管理(分析設(shè)計)《C++面向?qū)ο蟪绦蛟O(shè)計導(dǎo)論:從抽象到編程》章節(jié)的內(nèi)容目錄8課程成績管理應(yīng)用案例(1)8.2教師錄入成績的視圖8.3屬性的抽象和關(guān)聯(lián)的表示8.2教師錄入成績的視圖8.1場景分析本節(jié)學習目標能夠綜合運用本書中的知識分析設(shè)計一個實際應(yīng)用軟件能夠綜合運用面向?qū)ο笾R解釋分析設(shè)計的步驟及任務(wù)能夠針對每個步驟選擇適當?shù)腢ML工具來表達分析設(shè)計的過程及成果8.1場景分析課程成績管理系統(tǒng)的相關(guān)人員及其期望教師期望錄入成績學生期望查詢成績教學管理教師期望對成績進行統(tǒng)計分析,以評價教師的教學效果和學生的學習效果。教師、學生和教學管理教師在處理課程成績過程中,還要從教務(wù)系統(tǒng)中獲取教師、學生和課程,以及課程安排等基礎(chǔ)數(shù)據(jù)

管理課程成績的過程中,主要涉及教師、學生和教學管理教師,每類人員對課程成績管理系統(tǒng)有不同的期望。

從這些期望中獲取系統(tǒng)的需求,推導(dǎo)出系統(tǒng)的功能8.1場景分析

分析課程的組織實施場景,可發(fā)現(xiàn)學生、教師、教學管理教師、教學班、課程、課程成績、任課教師、教授課程、成績表、修讀學生、考試、考試成績、選課、及格、不及格、錄入、查詢等概念。排除不相關(guān)的概念合并相同的概念刪除重復(fù)術(shù)語找到課程成績管理中涉及的主要概念及其相互關(guān)系學校以教學班的形式組織課程教學每個教學班講授一門課程,安排一名教師授課,這名教師稱為任課教師(或主講教師)。每個教學班有多個學生聽課,這些學生稱為修讀學生。課程教學結(jié)束后,每名任課教師給本教學班中的每名修讀學生評定一個課程成績,形成這個教學班的成績表,并錄入到課程成績管理系統(tǒng)。每名學生能夠查詢所有已修讀課程的成績,并形成自己的課程成績表。教學管理教師也是教師,每名教學管理教師能夠查詢每個教學班的任課教師和教授的課程,也能夠進行統(tǒng)計分析,評價學生的學習效果和教師的教學效果。8.1場景分析課程成績管理中涉及的主要概念(教學班、教師、課程、學生、課程成績、教學管理教師)及其相互關(guān)系。多個教學班對應(yīng)一門課程8.2教師錄入成績的視圖教師使用課程成績管理系統(tǒng)的目的是錄入成績,主要關(guān)心的是課程成績、學生及教學班。從教師的角度調(diào)整課程成績管理的關(guān)系視圖。去掉涉及不到的事物按照與錄入成績的緊密程度進行調(diào)整8.2教師錄入成績的視圖將視圖中的概念視為“類”,將概念的外延包含的事物視為類的對象Teacher類GradeOfCourse類Student類Course類TeachingClass類8.3屬性的抽象和關(guān)聯(lián)的表示將概念的內(nèi)涵抽象出屬性,本案例可使用前人在長期教學組織管理的過程總結(jié)抽象的屬性。

其中“編號”類屬性(學號、教師編號、教學班編號、課程編號)叫標識屬性,其作用為:屬性值用于唯一標識對象使用這些屬性表示類之間的關(guān)聯(lián)8.3屬性的抽象和關(guān)聯(lián)的表示對象的標識和關(guān)聯(lián)的實現(xiàn)將教師錄入成績視圖進行調(diào)整,加入類屬性,到學生和教師的聚合關(guān)聯(lián)調(diào)整為一般關(guān)聯(lián)(它們是使用標識屬性來實現(xiàn)關(guān)聯(lián)),加入ManagerOfGrade類用來管理教學班。8.3屬性的抽象和關(guān)聯(lián)的表示對象屬性course表示到Course類的多對一聚合關(guān)聯(lián)容器屬性gradeTbl表示到GradeOfCourse類的一對多組合關(guān)聯(lián)標識屬性studentID表示到Student類的一對一一般關(guān)聯(lián)容器屬性studentTbl表示到Student類的多對多一般關(guān)聯(lián)標識屬性teacherNo表示到Teacher類的多對一一般關(guān)聯(lián)(分析設(shè)計一般采用自頂向下的順序)練習場景分析使用用例圖分析相關(guān)人員及其根本期望使用類圖分析其中的主要事物及其關(guān)系教師錄入成績的視圖涉及到的部分事物及其關(guān)系屬性的抽象和關(guān)聯(lián)的表示使用類的屬性描述事物(設(shè)計)使用類的屬性表示事物的關(guān)系(設(shè)計)按照如下的步驟,圍繞用例“教師錄入成績”重新做分析設(shè)計圍繞用例“學生查詢成績”重新做分析設(shè)計總結(jié)及進一步學習思維:概念抽象分析設(shè)計中的要素過程:分析設(shè)計的步驟及任務(wù)方法:每個步驟中所采用的方法工具:每個步驟中所選用的工具(圖)8.4-9課程成績管理(編碼實現(xiàn))進一步學習場景分析使用用例圖分析相關(guān)人員及其根本期望使用類圖分析其中的主要事物及其關(guān)系教師錄入成績的視圖涉及到的部分事物及其關(guān)系屬性的抽象和關(guān)聯(lián)的表示使用類的屬性描述事物(設(shè)計)使用類的屬性表示事物的關(guān)系(設(shè)計)章節(jié)的內(nèi)容目錄8.1場景分析第8章課程成績管理(編碼實現(xiàn))8.4-8.5相關(guān)關(guān)聯(lián)的邏輯實現(xiàn)8.6錄入成績的實現(xiàn)8.7學生查詢成績的實現(xiàn)8.8進一步努力方向8.4多對一關(guān)聯(lián)的邏輯實現(xiàn)8.5一對多關(guān)聯(lián)的邏輯實現(xiàn)8.6錄入成績的實現(xiàn)8.7學生查詢成績8.8進一步努力方向8.9程序員成才之路學習目標能夠綜合運用本書中的編程技術(shù)設(shè)計實現(xiàn)方案能夠使用C++語言編碼實現(xiàn)所設(shè)計的實現(xiàn)方案能夠綜合運用本書中的編程知識解釋實現(xiàn)方案及其編程方法8.4多對一關(guān)聯(lián)的邏輯實現(xiàn)一般應(yīng)按照與箭頭相反的方向編寫類的代碼,并實現(xiàn)從這個類發(fā)出的關(guān)聯(lián)。先編寫Teacher、Course和Student三個類,再依次編寫GradeOfCourse、TeachingClass,最后編寫ManagerOfGrade(編碼實現(xiàn)按照自底向上的順序)。8.4多對一關(guān)聯(lián)的邏輯實現(xiàn)使用標識屬性編碼實現(xiàn)多對一和一對一關(guān)聯(lián)課程成績GradeOfCourse的職責負責管理成績grade負責維護到一個學生Student對象的連接8.4多對一關(guān)聯(lián)的邏輯實現(xiàn)/*****使用成員函數(shù)訪問標識屬性****/intStudentBase::getStudentID(){returnstudentID;}voidStudentBase::setStudentID(int

newStudentID){ studentID=newStudentID;}/*****重載比較運算:用于排序****/boolStudentBase::operator==(constStudentBase&b)const{returnstudentID==b.studentID;}boolStudentBase::operator>(constStudentBase&b)const{returnstudentID>b.studentID;}boolStudentBase::operator<(constStudentBase&b)const{returnstudentID<b.studentID;}/*****重載類型轉(zhuǎn)換int:用于按studentID查找****/StudentBase::operator

int(){ returnstudentID;}【例8.1】

學生StudentBase中排序和查找所需的運算和成員函數(shù)8.4多對一關(guān)聯(lián)的邏輯實現(xiàn)#include

<algorithm>//Forsort()//省略后面的頭文件

/*****使用成員函數(shù)訪問屬性****/floatGradeOfCourse::getGrade(void){returngrade;}voidGradeOfCourse::setGrade(float

newGrade){//增加檢驗功能

if(newGrade>100||newGrade<0){ grade=-1; cerr<<"成績超出范圍:"<<newGrade<<endl; }

else grade=newGrade;}StudentGradeOfCourse::getStudent(vector<Student>&StudentTbl){

vector<Student>::iteratorit=find(begin(StudentTbl),end(StudentTbl),studentID);

if(it==StudentTbl.end()){ cerr<<"沒有連接到學生,創(chuàng)建失敗?。。?<<studentID<<endl; Student*p=NULL;

return(*p); }

else

return*it;}【例8.2】課程成績GradeOfCourse中存取連接的學生對象8.4多對一關(guān)聯(lián)的邏輯實現(xiàn)課程成績GradeOfCourse類的成員函數(shù):setStudentintGradeOfCourse::setStudent(intnewStudentID,vector<Student>&StudentTbl){ vector<Student>::iteratorit=find(begin(StudentTbl),end(StudentTbl),newStudentID);

if(it==StudentTbl.end()){ studentID=0;//沒有找到學生 cerr<<"沒有連接到學生,創(chuàng)建失?。?!"<<newStudentID<<endl; }

else studentID=newStudentID;

return

studentID}intGradeOfCourse::setStudent(Student&newStudent,vector<Student>&StudentTbl){ vector<Student>::iteratorit=find(begin(StudentTbl),end(StudentTbl),newStudent.getStudentID());

if(it==StudentTbl.end()){ cerr<<"沒有找到學生:"<<newStudent.getStudentID()<<endl; studentID=0; }

else studentID=newStudent.getStudentID();

return

studentID}8.4多對一關(guān)聯(lián)的邏輯實現(xiàn)#include

<algorithm>

//Forsort()#include

<functional>

//Forgreater<int>()//省略后面的頭文件

voidmain(){ vector<Student>st;

intcnt=readData(st); cout<<"成功讀取"<<cnt<<"個學生的信息"<<endl;

cout<<"對學生信息按學號降序排序"<<endl; sort(st.begin(),st.end(),greater<Student>());

GradeOfCoursegc1,gc2; cout<<endl<<"創(chuàng)建GradeOfCourse對象及其連接"<<endl; gc1.setStudent(st[0],st); gc1.setGrade(67); cout<<"創(chuàng)建對象:"<<gc1<<endl;

cout<<"取出連接的Student對象"<<endl; Students1=gc1.getStudent(st);

if(NULL==&s1)//判斷是否連接到一個Student對象 cout<<"沒有連接到學生??!"<<endl;

else cout<<s1<<endl;

cout<<"創(chuàng)建GradeOfCourse對象及其連接"<<endl; Students2; s2.setStudentID(123); gc2.setStudent(s2,st);}讀入學號錯誤!成功讀取33個學生的信息對學生信息按學號降序排序

創(chuàng)建GradeOfCourse對象及其連接創(chuàng)建對象:20215967

取出連接的Student對象202159文杰

創(chuàng)建GradeOfCourse對象及其連接沒有找到學生:123

【例8.4】

教學班TeachingClass中維護課程成績表的主要代碼8.5一對多關(guān)聯(lián)的邏輯實現(xiàn)使用容器存儲管理連接的對象,編程實現(xiàn)多對多和一對多關(guān)聯(lián)選擇list存儲管理GradeOfCourse對象選擇vector存儲管理Student對象8.5一對多關(guān)聯(lián)的邏輯實現(xiàn)【例8.4】教學班TeachingClass中維護課程成績表的主要代碼TeachingClass::TeachingClass(vector<Student>&st):gradeTbl(0),course(){ studentTbl=st;}intTeachingClass::insertGrade(intstudentID,floatgrade){ GradeOfCoursegc;

if(gc.setStudent(studentID,*studentTbl))

return1;

else

if(gc.setGrade(grade))

return-1;

else{ gradeTbl.push_back(gc); gradeTbl.sort();

return0; }}intTeachingClass::modifyGrade(intstudentID,floatgrade){ deleteGrade(studentID);

returninsertGrade(studentID,grade);}intTeachingClass::deleteGrade(intstudentID){

intrt=0; list<GradeOfCourse>::iteratorit=find(gradeTbl.begin(),gradeTbl.end(),studentID);

if(!(NULL==*it)){ gradeTbl.erase(it); rt=1; }

returnrt;}

list<GradeOfCourse>&TeachingClass::getGradeTbl(void){

returngradeTbl;}GradeOfCourseTeachingClass::findGradeByID(intstudentID){ list<GradeOfCourse>::iteratorit=find(gradeTbl.begin(),gradeTbl.end(),studentID);

if(NULL==*it)

return*it;

else{ GradeOfCourse*p=NULL;

return*p; }}8.5一對多關(guān)聯(lián)的邏輯實現(xiàn)【例8.5】錄入一個教學班的學生成績voidmain(){ vector<Student>st;

intcnt=readData(st); cout<<"成功讀取"<<cnt<<"個學生的信息"<<endl;

//cout<<"對學生信息按學號降序排序"

溫馨提示

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

最新文檔

評論

0/150

提交評論