面向对象程序设计课件_第1页
面向对象程序设计课件_第2页
面向对象程序设计课件_第3页
面向对象程序设计课件_第4页
面向对象程序设计课件_第5页
已阅读5页,还剩205页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

面向對象程式設計

第一章面向對象的基本概念軟體的外部品質正確性健壯性可擴充性可複用性第一章面向對象的基本概念2.模組化模組化標準模組的可分解性(圖1.1)模組的可結合性(圖1.3)模組的可理解性(圖1.4)模組的連續性模組保護模組化原則語言模組單元資訊隱藏原則第一章面向對象的基本概念軟體複用代碼複用設計過程複用分析方案複用第一章面向對象的基本概念為什麼要面向對象程式中各種成分的特點:介面:極為易變功能:很易變過程執行順序:很易變數據:極為易變對象:最為穩定面向功能的方法的缺陷:可擴充性、可維護性、複用性的問題。第一章面向對象的基本概念5.面向對象的基本概念面向對象的含義面向對象開發的含義面向對象的主題面向對象的含義面向對象是把軟體系統看成是一系列對象的集合對象包括數據結構,也包括行為面向對象的四個特性標識唯一性分類性多態性繼承性標識唯一性每一個對象都有一個唯一的標識通過標識找到對象對象的查找方法統一且獨立於對象的內容分類性具有相同數據結構和行為的對象構成一個類。類是一種抽象:它反映了與應用有關的重要性質,而忽略了一些無關的內容。多態性同一個操作可以是不同的類的行為繼承性類之間形成一種層次性的結構。父類的性質可以被子類繼承。減少了程式設計的重複性。代碼複用快速原型技術面向對象開發的含義建摸開發過程中真正有意義的成效來自於對象的概念,而不是實現。方法學分析系統設計對象設計實現面向對象開發的含義(續)三種模型對象模型動態模型功能模型對象模型對象模型即描述對象的結構對象的唯一標識與其它對象的關係對象的屬性對象的操作動態模型動態模型描述與時間和操作次序有關的系統屬性:觸發事件事件序列事件狀態事件與狀態的組織動態模型關心的是控制。動態模型用狀態圖來表示。功能模型功能模型描述與值的變化有關的系統屬性:功能、映射、約束、依賴條件等功能模型用數據流圖表示。模型之間的關係對象模型描述了動態模型和功能模型中的數據結構;對象模型中的操作對應於動態模型中的事件和功能模型中的功能。動態模型描述了對象模型中對象喚醒、和動態模型中行為的喚醒的功能。功能模型說明說明對象模型中操作的含義和動態模型中的行為的意義,以及對象模型中約束的意義。面向對象的主題抽象封裝歸併數據與行為共用抽象強調實體的本質、忽略無關緊要的屬性決定對象時:研究對象的意義和行為繼承性強化了抽象的機制:避免過早地考慮細節問題封裝對象的內部實現細節對象獨立的外部性質分離實現細節與介面合併數據與行為歸併數據與行為類層次過程層次數據層次共用在同一個應用專案中共享:繼承在不同的專案中共享:類庫#include<iostream.h>voidmain(){ intj=3; cin>>j; cout<<“j=“<<j<<endl;}2.關於注釋/*comments*/編譯程序略去注釋對之間的內容//comments編譯程序略去注釋符後面的內容3.預處理#include#include<….h>在系統指定的目錄中尋找頭檔#include“…h”在系統當前目錄中尋找頭檔3.預處理#define#include<iostream.h>#defineHELLO"Hello,world!"voidmain(){ cout<<HELLO<<endl;}3.條件預處理#if,…#include<iostream.h>#defineDEBUG0voidmain(){ intj; j=5;#ifDEBUG cout<<"j="<<j<<endl;#endif}3.條件預處理#ifdef,…//2_5_4.cpp#include<iostream.h>#include"2_5_4.h"#include"2_5_4_1.h"voidmain(){ cout<<"x="<<x<<endl;}//2_5_4.h#defineXDEFintx=2;//2_5_4_1.h#ifndefXDEFintx=2;#endif4.數據類型的初步知識基本數據類型char,int,float,double,void修飾符signedunsignedlongshort4.數據類型的初步知識#include<iostream.h>voidmain(){ cout<<sizeof(char)<<endl; cout<<sizeof(int)<<endl; cout<<sizeof(float)<<endl; cout<<sizeof(double)<<endl; cout<<sizeof(longdouble)<<endl;}輸出結果:144884.數據類型的初步知識複合數據類型結構聯合位域枚舉類5.常量整型常量浮點常量字元常量字串常量6.變數變數的意義變數名匈牙利命名法:小寫字母開始表示變數類型其餘的名字表示變數的功能。例如;nCharacterCounter

整型變數、保存字元數。保留字不能作變數名變數的定義7.指針類型定義:類型*指針類型變數初始化同類型變數的左值:*p=&x;同類型指針變數:p=q;動態分配的地址:int*p=new(int);int*p=malloc(sizeof(int));7.指針類型指針運算#include<iostream.h>voidmain(){ inti=1,j=2,k=3; int*p=&j; p=p+1; *p=*p+2;

cout<<i<<endl; cout<<j<<endl; cout<<k<<endl;}輸出結果:323#include<iostream.h>voidmain(){ char*st="Theexpenseofspirit"; intlen=0; char*p=st; while(*p++)len++; cout<<len<<":"<<st<<endl;}#include<iostream.h>voidmain(){ char*st="Theexpenseofspirit"; intlen=0; while(*st++)len++; cout<<len<<":"<<st<<endl;}8.引用類型定義intval=10;int&refVal=val;refVal+=2;//nowval=128.引用類型引用必須初始化不能再作其他變數的引用引用可以直接由一個右值去初始化,這時一個內部的臨時變數用於取得這個右值,然後引用使用這個臨時變數來進行初始化用不同類型的對象初始化時,同樣會由系統生成一個臨時變數。9.常量類型const必須被初始化定義後就不能被改變常量的地址不能被賦給一個指針constinta=3;int*p=&a;9.常量類型常量的指針:指針指向一個常數常量指針能再指向其他地址constint*p;intj,k;p=&j;p=&k;常量指針所指的對象不能通過這個常量指針來改變值constint*p;intj;p=&j;*p=*p+1;9.常量類型指針常量:指針是一個常量,但所指的變數未必是常量定義interrNum;int*constcurErr=&errNumb;可以改變指針常量所指的對象*curErr=1;*curErr=2;不可以改變指針常量curErr=&x;curErr=y;//Error例:程式2_11_1.10.枚舉類型枚舉類型是整型符號常量的集合。枚舉類型對象中的元素沒有記憶體地址。在默認的情況下第一個元素的值為0。每一個元素都可以被明確賦值。一個元素若沒有被明確賦值,則它的值是前一個元素的值加1。舉例11.數組類型一維數組:類型變數[數組大小];二維數組:類型變數[數組大小][數組大小];數組類型與指針的關係:&buf[0]與buf具有相同的意義。數組名不能運算:++buf是錯誤的。12.自定義類型名定義:typedef類型自定義類型;作用改善聲明過程:舉例2_15.cpp移植的方便typedefintADDRADDRa;ADDRb;typedeflongADDRADDRa;ADDRb;3.10類型轉換類型轉換:不改變二進位的結構,但用不同的方式解釋這些數據。3.10.1隱式類型轉換在算術運算式中,具有較大空間的數據類型成為最終結果轉換成的數據類型。例如:intval=3.14159;//轉換成3val+3.14159;//val先轉換成3.0,結果6.14159例intI=10;I*=2.3;cout<<I;運行結果:233.10.2顯式類型轉換在{intk;k=k+3.14159;}中將k轉化成double;計算運算式值將運算式的類型轉化成int在{intk;k=k+(int)3.14159;}中只有一次類型轉換void*的指針可以指向任何數據,但不能直接引用void*的指針不能直接賦值給其他類型的指針void*用於對象類型未知或隨狀態而改變的情況3.10.2顯式類型轉換#include<iostream.h>voidmain(){ inti=10; //int*ip; void*vp; doubled=3.14159; //ip=&d;//cannotconvertfrom'double*'to'int*' vp=&d; cout<<*(double*)vp<<endl;}3.10.2顯式類型轉換{ void*vp; double*dp; doubled=3.14159; vp=&d; //dp=vp;//error:cannotconvertfrom'void*'to'double*' dp=(double*)vp;}3.11語句用分號結束一條語句最簡單的語句是“空語句”:;複合語句用花括弧括起來的一系列語句組成複合語句作未一個單一的單元出現在單一語句出現的任何地方複合語句不需要以分號終結3.12if語句語法結構:if(運算式)語句運算式必須放在括弧中。運算式為非0時,表示真,並執行語句容易出現的錯誤1:經常忘了複合語句的花括弧3.12if語句#include<iostream.h>voidmain(){ inti=0; if(i) cout<<"first"<<endl; cout<<"second"<<endl;}輸出結果:second3.12if語句#include<iostream.h>voidmain(){ inti=0; if(i){ cout<<"first"<<endl; cout<<"second"<<endl; }}這個程式沒有輸出3.12if語句if-else語句:if(運算式) 語句1else

語句2語句1若不是複合語句則必須有分號

3.12if語句嵌套的if語句中else匹配的時離它最近的if語句:if(exp1) if(exp2) s1; else s2;

#include<iostream.h>voidmain(){ intk=0,n=1; if(k) if(n) cout<<"first"<<endl; else cout<<"second"<<endl;}//3_12_2.cpp沒有輸出#include<iostream.h>voidmain(){ intk=0,n=1; if(k){

if(n) cout<<"first"<<endl;}

else cout<<"second"<<endl;}輸出:second#include<iostream.h>#definesize5voidmain(){ intia[size]={3,1,2,9,1}; intminVal=ia[0]; intoccurs=1; for(inti=1;i<size;i++){ if(minVal==ia[i]) ++occurs; else

if(minVal>ia[i]){ minVal=ia[i]; occurs=1; } } cout<<"minVal="<<minVal<<endl; cout<<"occurs="<<occurs<<endl;}3.13switch語句格式:Switch(運算式){

caseexp1:語句1;break; …………….. caseexpn:語句n;break;}exp1,…expn都是常量運算式如果語句1,…,語句n後沒有break,則繼續執行下一行語句。3.13switch語句Default語句Switch(運算式){

caseexp1:語句1;break; …………….. caseexpn:語句n;break; default:語句n+1;}3.14迴圈語句3.14.1while語句格式及意義while(運算式)語句只要運算式真,就執行循環體語句。例3_14.cpp3.14.2

for語句格式for(init_statement;expr1;expr2)語句語義執行init_statement;計算expr1;如果expr1非0,則執行語句;否則結束for語句。執行expr2;轉23.14.2

for語句for(;;)無限迴圈#include<iostream.h>voidmain(){ inti=0; for(;;){ if(i>5)break; cout<<i<<endl; i++; }}3.14.3

do語句格式do

語句while(expr);#include<iostream.h>voidmain(){ inti=0; do cout<<i++<<endl; while(i<5);}4.1成員變數和成員函數4.1類的定義定義類:classStack{ …};定義類並說明對象classStack{ …}obj1,obj2;4.1.2成員變數1.與聲明變數的方式相同聲明中不允許進行初始化賦值classStack{ int*lst; intmax_size; intnb_elements;};classStack{ int*lst; //error intmax_size=0; intnb_elements;};4.1.2成員變數3.成員變數可以使任何類型classStack{ int*lst; intmax_size; intnb_elements; Stack*s;};classStackofStack{ inttopStack; Stackstackstorage[5];};4.1.2成員變數4.提前聲明:一個類提前聲明之後,這個類的對象指針、引用可以作為另一個類的成員變數。

classStack;classStackofStack{ inttopStack; Stack*stackstorage;};

但這個類的對象不能作另一個類的成員變數。4.1.3成員函數在定義體外定義4_1_2.cppclassStack{ intempty(); voidpop(); inttop(); voidpush(int);};intStack::empty(){return(nb_elements==0);}4.1.3成員函數在定義體內定義4_1_2.cppclassStack{ intempty(){return(nb_elements==0);} voidpop(); inttop(); voidpush(int);};4.1.4資訊隱藏原則:將類的功能描述部分作為共有部分介面提供給用戶;將數據的具體表示、具體實現作為私有部分隱藏起來。成員函數友元派生類其他privateYNNprotectedYYNpublicYYY4.1.4資訊隱藏例共有部分-私有部分intempty();voidpop();inttop();voidpush(int);int*lst;intmax_size;intnb_elements;4.1.5對象與類類對象對象的說明類對象1,對象2,對象n;4_1_2.cpp4.1.6const成員函數聲明為const的對象是不能被賦值的聲明為const的對象不能隨便調用任意的成員函數聲明為const的對象只能調用聲明為const的成員函數const的成員函數不能改變成員變數4.2構造函數與析構函數構造函數4.2構造函數和析構函數4.2.1對象的初始化構造函數用來在聲明對象時,初始化成員變數。4_2_1.cpp如果定義了構造函數,則在聲明對象時所帶參數類型必須與某一個構造函數的的參數類型一致。4_2_1.cpp如果沒有定義構造函數,則在聲明對象時不帶參數。4_2_0.cpp4.2.2構造函數的定義構造函數不允許指明返回類型,也不允許返回一個值。構造函數的名字必須與類的名字一樣。構造函數可以重載:有多種定義,每一種定義的參數表不一樣。聲明對象時參數類型必須與一個構造函數的參數類型一致。構造函數一般說明為public。例4_2_2.cpp構造的調用:明確調用方式Strings1=String(“rose”);Strings2=String(3);Strings3=newString(“rose”);簡化調用方式Strings3(“rose);Strings4=“rose”;例4_2_3.cpp用無參數構造函數初始化對象不定義任何構造函數定義無參數的構造函數例:4_2_4.cppStrings();不是聲明無參數的對象,而是不帶參數的返回類型String型對象的函數。4.2.3析構函數4.2.3.1對象的生存期對象的生存期4_2_3_1.cpp一個對象在退出作用域時,系統要回收其空間。在退出對象指針時,如果沒有調用delete則不會釋放指針所指的空間。4.2.3.2系統回收空間LenStrLenStrLenStr{deletestr;}{}LenStr系統回收垃圾空4.2.3.3析構函數格式:~類名();析構函數不帶參數,沒有返回值。例4_2_3_2.cpp4.2.3.4顯式調用析構函數如果只想執行析構函數中的執行的操作,而不釋放對象的空間,則可以顯式調用析構函數。pb->String::~String();執行析構函數中的執行的操作。pb->~String();執行系統的析構函數,釋放對象的空間。4.2.4類/對象數組定義constsize=16Stringtbl[size];String*tbl=newString[size];訪問數組對象tbl[I].display();4.2.4類/對象數組初始化Strings[]={“rose”,“sbeef”};Stringt[]={String(),String(3);String(“rose”)};刪除delete[2]s;delete[3]t;4.2.5對象成員構造函數的執行次序:對象成員的構造函數先初始化,然後才是包含它的類的構造函數。有多個對象成員時,按照在類的定義中聲明的次序初始化。4_2_5_1.cpp對象成員的初始化參數由初始化表提供。初始化表只能出現在構造函數的定義體中,不能出現在構造函數的聲明中。(MSVC++沒有這個限制。)4.2.5對象成員const成員必須在成員初始化表中初始化。4_2_5_2.cpp。成員對象的初始化參數可以是同一類型的另一個對象。4_2_5_3.cpp。多層成員對象初始化的次序。4_2_5_3.cpp。4.2.6成員初始化通過另一個對象初始化編譯器定義的拷貝函數X::X(const&X);String::String(const&String&s){ len=s.len; str=s.str;}//淺拷貝4_2_6.cpp4.2.7構造函數X::X(const&X)String::String(constString&s){ len=s.len; str=newchar[len+1]; strcpy(str,s.str);};//深拷貝4_2_7.cpp4.3靜態成員變數和靜態成員函數某個類的所有對象都共同訪問同一個變數。全局變數的缺點靜態成員變數類的所有對象都共用靜態成員變數圖4.7聲明:static類型變數初始化:類型類名::變數=初始值;初始化時不加static初始化時不用加private、public、protected初始化時用域作用符::說明所屬類。4.4內聯函數使c++編譯器在函數調用處以代碼體內聯來替換對函數的調用。4.5友元成員函數派生類其他privateYNNprotectedYYNpublicYYY4_5_1.cpp4.6對象和動態對象4.6.1this指針一個類所有的對象的成員變數除了靜態變數外都有獨立空間,但同一個類的所有對象成員共用同一組成員函數。一個對象調用自己的成員函數時,將this指針傳遞給這個成員函數,這個this指針指向這個對象。例:4_6_1_1.cpp4.6.1this指針成員函數翻譯成非成員函數voidStack::empty(){ return(nb_elements==0);}voidempty__Stack(Stack*this){ return(this->nb_elements==0);}成員函數翻譯成非成員函數voidStack::push(intelements){ if(nb_elements<max_size) lst[nb_elements++]=elements;}voidpush__Stack(Stack*this,intelements){ if(this->nb_elements<this->max_size) lst[this->nb_elements++]=elements;}連續操作,返回this指針4_6_1_2.cpp4.6.2動態對象用new代替malloc、alloc等用delete代替free變數指針=new類型;變數指針=new類型(初始值);變數指針=new類型[size];變數指針=new類型[size][size];delete變數指針;delete[size]變數指針;初始化與數組對象用new分配一個對象時,可以直接初始化。用new分配一個對象數組時,不可以直接初始化,並且對象必須有一個無參數構造函數。例:4_6_2_1.cpp例:4_6_2_2.cpp例:4_6_2_3.cpp5.1結構5.1.1結構的定義與結構變數的聲明structexample{inta; floatb;}structexamplee1,e2;typedefstructexample{inta; floatb;}EXAMPLE;EXAMPLEe1,e2;5.1結構5.1.1結構的定義與結構變數的聲明structexample{inta; floatb;}examplee1,e2;structexamplee3,e4;5.1.2結構作為類結構中也可以引入成員函數在缺省的情況下結構的成員是public例:5_2_1.cpp5.2.1聯合作為類聯合的成員變數共用記憶體同一個單元在缺省的情況下,聯合成員是公有的聯合可以包含成員函數聯合不能繼承其他的類聯合不能有序函數靜態變數不能是聯合如果有構造、析構函數,則對象不能是聯合的成員例:5_2_1_1.cpp5.2.2匿名聯合匿名聯合不含類型名變數不能被說明為這類聯合聯合的成員變數要共用同一個單元聯合的變數直接引用例:5_2_2_1.cpp匿名聯合不能有成員函數匿名聯合不能有private,protected全局匿名聯合必須是靜態的。6.1函數函數的聲明[inline][返回類型]函數名(形式參數表);形式參數表:[類型[變數名]{,類型[變數名]}]例:voidf(int);intgcd(int,int);inlineintmin(intj,intk);6.1.1遞歸一個函數如果直接或間接地調用自身稱為遞歸函數。例6_1_1_1.cpp6.1.2內聯函數內聯函數與直接代碼比較的優點可讀性容易修改類型檢查複用6.1.3強類型檢查所有函數調用的參數表和返回值都要進行類型檢查。如果一個實參類型與函數原型聲明的形式參數不匹配,則首先使用隱式類型轉換,若隱式類型轉換無法進行,或參數個數不符,則給出編譯錯誤。6.1.4返回值數組類型、函數類型不能作為返回類型。數組類型的指針、函數類型的指針可以作為返回類型。默認的返回類型是int。6.1.5函數參數表參數表語法結構intfork();intfork(void);等價。函數聲明中可以只出現類型不出現參數名。有參數名可以增加可讀性。函數定義中必須出現類型和出現參數名。參數個數不定的參數表例6_1_5_1.cpp有缺省值參數有缺省值參數必須放在最後6.1.6參數傳遞傳值參數傳遞將實際參數的右值複製到形式參數的存儲空間。不適合傳遞大量數據不適合返回計算結果指針參數傳遞引用參數例:6_1_6_1.CPP6.1.7引用參數參數傳遞方式類似與指針參數傳遞程式書寫方式類似與傳值參數傳遞6.1.8數組參數一下三種聲明等價:voidf(int*);voidf(int[]);voidf(int[10]);編譯器和函數都不檢查數組參數的個數voidf(int*,intsize);voidf(int[],intsize);voidf(int[10],intsize);6.1.8數組參數多維數組參數

intf(intmatrix[][10],introwSize);intf(int(*matrix)[10],introwSize);6.1.9作用域檔域局部域、局部塊域類域域操作符:::使程式可以處理被隱藏的外部變數外部變數靜態外部變數6.1.10局部域將局部變數的地址傳出是一個嚴重的錯誤:intf(inta,intb){ return&a;}靜態局部變數寄存器型局部變數作業建立一個保存整數的環形佇列存放數據讀取數據。。。。。6.1.6參數傳遞傳值參數傳遞將實際參數的右值複製到形式參數的存儲空間。不適合傳遞大量數據不適合返回計算結果指針參數傳遞引用參數例:6_1_6_1.CPP6.1.7引用參數參數傳遞方式類似與指針參數傳遞程式書寫方式類似與傳值參數傳遞6.1.8數組參數一下三種聲明等價:voidf(int*);voidf(int[]);voidf(int[10]);編譯器和函數都不檢查數組參數的個數voidf(int*,intsize);voidf(int[],intsize);voidf(int[10],intsize);6.1.8數組參數多維數組參數

intf(intmatrix[][10],introwSize);intf(int(*matrix)[10],introwSize);6.1.9作用域檔域局部域、局部塊域類域域操作符:::使程式可以處理被隱藏的外部變數外部變數靜態外部變數6.1.10局部域將局部變數的地址傳出是一個嚴重的錯誤:intf(inta,intb){staticintk; return&a;}靜態局部變數寄存器型局部變數6.2.1動態分配空間例6_2_1.cppIntArray中的ia所指的空間是動態分配的,ia本身是靜態分配的。在局部域中的對象進入局部域時分配空間,推出時系統自動返回空間。動態分配的空間必須顯示地回收空間。6.2.2一個鏈接表的例子6_2_2_1.cpp6.2.3函數重載兩個及兩個以上不同的函數共用一個函數名,利用函數的參數表來區別。intmax(int,int);doublemax(double,double);complex&max(complex&,complex);intimax(int,int);doubledmax(double,double);complex&cmax(complex&,complex);6.2.3函數重載參數表和函數名相同的兩個函數被認為是重定義。不適合函數重載的情況不同的函數的操作沒有類似的地方重載函數的調用完全匹配參數轉換引用參數類型的匹配類型必須完全匹配多個參數的調用:6_2_3_7_1.cpp參數的隱含值重載與作用域重載new6.2.4指向函數的指針函數類型指針返回類型(*函數指針名)(參數表);函數名同時也表示指向該函數的指針若voidf(),則f與&f具有相同的類。初始化與賦值voidf(){cout<<"f:"<<endl;}voidg(){cout<<"g:"<<endl;}void(*pf)();voidmain(){ pf=f;pf(); pf=g;pf();}函數指針數組Int(*pfArray[10])(int);例:6_2_4_1.cpp函數指針數組初始化void(*_new_handler)()指向無返回參數無參數的函數的指針。當new分配失敗時,測試該指針是否指向了一個函數,如果它為被賦值,則new返回0,否則調用該指針指向的函數。構造函數調用順序基類的構造函數內部成員對象的構造函數派生類的構造函數析構函數的調用順序與構造函數調用順序相反函數重載時參數的傳遞首先檢查是否由完全匹配在檢查是否有通過標準轉換的匹配通過標準轉換後有多種匹配,則報告ambiguous匹配錯誤。例:6_3_1.cpp全局靜態變數全局靜態變數的作用外部變數靜態局部變數、局部塊域例:6_3_3.cpp值參例:6_3_4.cpp#include<iostream.h>voidf(inti){ cout<<i<<endl;}voidmain(){ inti=1;f(i);}8:f(i);004010CFmoveax,dwordptr[ebp-4]004010D2pusheax004010D3call@ILT+15(f)(00401014)004010D8addesp,49:}指針參數#include<iostream.h>voidf(int*i){ cout<<i<<endl;}voidmain(){ inti=1;f(&i);}8:f(i);004010CFleaeax,[ebp-4]004010D2pusheax004010D3call@ILT+35(f)(00401028)004010D8addesp,49:}引用型參數#include<iostream.h>voidf(int&i){ cout<<i<<endl;}voidmain(){ inti=1;f(i);}8:f(&i);004010CFleaeax,[ebp-4]004010D2pusheax004010D3call@ILT+30(f)(00401023)004010D8addesp,49:}用引用返回值例:6_3_5.cpp#include<iostream.h>floattemp;floatfn1(floatr){ temp=r*r*(float)3.14; returntemp;}float&fn2(floatr){ temp=r*r*(float)3.14; returntemp;}voidmain(){ floata=fn1(5.0); //float&b=fn1(5.0); floatc=fn2(5.0); float&d=fn2(5.0); cout<<a<<endl; //cout<<b<<endl; cout<<c<<endl; cout<<d<<endl;}floata=fn1(5.0);fn1r5.0臨時變數atemp78.5floatc=fn2(5.0);fn1r5.0臨時變數ctemp78.515:floatc=fn2(6.0);00401118push40C00000h0040111Dcall@ILT+20(fn2)(00401019)00401122addesp,400401125moveax,dwordptr[eax]00401127movdwordptr[ebp-8],eaxFloat&d=fn2(5.0);fn1r5.0臨時變數d&temptemp78.516:float&d=fn2(7.0);0040112Apush40E00000h0040112Fcall@ILT+20(fn2)(00401019)00401134addesp,400401137movdwordptr[ebp-0Ch],eax7.1類的層次概念層次與複用成員的繼承類的兩種使用方法:實例化使用繼承使用將概念和實現轉變成類層次派生類是基類的具體化派生類是基類的延遲定義派生類是基類的組合7.2單繼承定義格式class派生類名:[訪問控制]基類名{

成員列表}訪問控制privateprotectedpublic公有基類基類的公有成員等價於派生類的公有成員。派生類的對象及其成員函數可以訪問基類的公有成員。保護基類基類的公有成員等價於派生類的保護成員。派生類的成員函數可以訪問基類的公有成員。派生類的對象不可以訪問基類的公有成員。私有基類基類的公有成員等價於派生類的私有成員。只有派生類的成員函數可以訪問基類的私有成員。部分公開使基類部分公有成員成為派生類的公有成員。base::成員名;在派生類中訪問聲明不允許對基類成員中私有成員進行訪問。例:7_2_1_2.cpp基類性質繼承性質派生類性質publicpublicpublicprotectedpublicprotectedprivatepublic不能訪問publicprotectedprotectedprotectedprotectedprotectedprivateprotected不能訪問publicprivateprivateprotectedprivateprivateprivateprivate不能訪問7.2.2成員訪問控制公有基類基類成員對基類對象的可見性:公有成員可見,其他不可見。基類成員對派生類的可見性:公有成員和保護成員可見,私有成員不可見。基類成員對派生類對象的可見性公有成員可見,私有成員和保護成員不可見。例:7_2_2.cppclassbase{ private:inti1; protected:intj1; private:intf1();};classdrv:publicbase{ private:inti2; protected:intj2; public:intf2();};Voidmain(){drvd1;}保護基類基類成員對基類對象的可見性:公有成員可見,其他不可見。基類成員對派生類的可見性:公有成員和保護成員可見,私有成員不可見。公有成員和保護成員對派生類的派生類的成員可見基類成員對派生類對象的可見性所有成員都不可見私有基類基類成員對基類對象的可見性:公有成員可見,其他不可見。基類成員對派生類的可見性:公有成員和保護成員可見,私有成員不可見。所有成員對派生類的派生類的成員不可見基類成員對派生類對象的可見性所有成員都不可見7.2.3構造函數參數的傳遞派生類名::派生類名(派生類參數表):基類名(基類參數表){

派生類初始化代碼

}基類沒有構造函數或構造函數沒有參數基類有構造函數且構造函數都有參數構造函數調用順序基類的構造函數內部成員對象的構造函數派生類的構造函數析構函數的調用順序與構造函數調用順序相反例:7_2_3_1.cpp例子7_2_4_1.cpp7_2_4_2.cpp多繼承的概念繼承所有基類的成員變數和成員函數inta;intb;intc;inta;intx;inty;inta;intb;intc;inta;intx;inty;intk;多繼承的定義格式:Class派生類:訪問控制基類[,訪問控制基類]{定義體}當有多個同名的繼承成員時,可以用域說明符號::來限定。例:7_3_0_1.cpp構造函數的調用順序基類的構造函數成員對象的構造函數派生類的構造函數例:7_3_0_1.cpp析構函數的調用順序派生類的析構函數成員對象的析構函數基類的析構函數多重公共基類parentprivate1private2derived_1:virtulparentprivate1private2private3derived_:virtulparent2private1private2private4derived_1_2private1,private2,private3,private4,private12例:7_3_2_1.cpp虛基類虛基類的意義在繼承路徑上,所有虛基類的成員變數只有一份。虛基類的構造函數必須由最新派生出來的類負責初始化虛基類的構造函數先於非虛基類的構造函數執行。例:若定義classL{...};classA:virtualL{...};classB:virtualL{...};classC:B,A{...};

則在類C中只有一份類L的成員變數。例:7_2_3_2.cpp虛基類parentprivate1private2derived_1:virtualparentprivate1Private2private3derived_2:virtualparentprivate1Private2private4derived_1_2private1,private2,private3,private4,private12例:7_3_2_2.cpp二義性問題(1)classL{public:voidf();};classA{public:intf();};classB:publicL,publicA{public: voidg(){f();}};這個例子中g()的訪問f()具有二義性,報告語法錯誤。可以L::f();或A::f();的形式訪問,即用類名加以限制。二義性問題(2)二義性檢查在訪問控制之前,因此當不同的基類成員中有相同的成員函數名時,就會出現二義性,及時由於訪問控制的限制,只有一個成員可見。如果A是B的基類,類A與B都有成員函數f(),則稱B::f()支配A:f()。有支配關係的兩個名字不會出現二義性。7_3_3_1.cpp7.3.4實例7_3_4_1.cppdata_recStaff:virtualdata_recstudent:virtualdata_recstudent_staffprofessorstudentlast_name;first_namestreet_address;citystate;zip;majorid_number;level;Stafflast_name;first_namestreet_address;citystate;zip;depthourly_wage;運算符重載例:8_2_1.cpp自定義的類的運算往往用函數來實現運算符重載l

運算符重載的目的:擴充語言的功能,即將運算符擴充到用戶定義的類型上去。l

除了.、.*、::、?、:其他都可以重載。l

delete、new、指針、引用也可以重載。l

運算符函數可以定義為內聯函數。l

用戶定義的運算符不改變運算符的優先次序。l

不可以定義系統定義的運算符集之外的運算符。不能改變運算符的的語法結構。雙目運算符重載8.2.1雙目運算符重載可進行重載的雙目運算符:*/%+-<<>><><=>=!=&^|&&||雙目運算符重載的聲明格式:class類名{類型operator運算符(參數);}雙目運算符重載的定義格式: 類型類名::operator運算符(參數);this指針:一個對象調用它的成員函數時,系統會傳給它一個指針this,指向對象自己。雙目重載時,this指向運算符左邊的對象。例:8_2_1_1.cpp友元運算符重載聲明:friend類型operator運算符(參數表);定義:類型operator運算符(參數表){……};例:8_2_1_2.cpp成員與友元運算符函數的區別參數個數不同this指針8_2_1_3.cpp8_2_1_4.cpp單目運算符重載不帶參數的成員函數8_2_2_2.cpp8_2_2_4.cpp帶有一個參數的友元函數8_2_2_1.cpp參數必須是引用不繼承=,繼承+8_2_2_3.cpp幾個特殊的運算符號重載[]重載8_2_3_1.cppX[k]解釋為X.operator[](k)()重載8_2_3_1.cppX(arg)解釋為X.operator()(arg)虛函數在選擇要調用的函數時有幾種方法來選擇根據參數的特徵來選擇:同一個類可以用同一個函數名來定義不同的多個函數,它們用參數類型來區分。根據作用域來確定:每個函數都有它的可見的區域。根據類的對象來確定:每個對象都有自己實現的函數的版本。前期聯編與後期聯編前期聯編:在編譯時刻就能夠確定要調用的函數後期(動態)聯編:在運行時刻才能確定要調用的函數為什麼需要虛函數一個類中的多個函數的名字可以有相同的名字,但是它們的函數特徵(參數類型與個數)必須不同

基類的函數名與派生類的函數可以同名且函數特徵(參數類型與個數)完全一致,派生類的對象會調用自己的函數。可以以一個指向基類對象的指針去訪問指向派生類的對象,在前期聯編的情況下,調用基類的成員函數,只在動態聯編的情況下會調用派生類的成員函數。

基類與派生類間指針轉換的幾條原則指向派生類對象的指針無需進行顯示轉換就能賦給基類對象:parent*p;derived*d;p=d;基類對象的指針不進行顯示轉換就不能賦給派生類對象:parent*p;derived*d;d=p;是錯誤的。基類對象的指針進行顯示轉換後就能賦給派生類對象:parent*p;derived*d;d=(derived*)p。不能以一個指向派生類對象的指針去訪問基類的對象,但可以以一個指向基類對象的指針去訪問指向派生類的對象。若沒有使用強制類型說明,基類對象指針不能訪問在派生類中定義的成員。

指向基類對象的指針可用於指向任何從它派生出來的類對象。8_3_1_4.cpp虛函數的意義告訴編譯程序確定一個對象的指針所指的成員函數的問題應等到運行時刻,檢查這個指針到底指向哪個對象,基類對象還是派生類對象,調用指針實際所指的對象的成員函數。例:8_3_1_1.cpp例:8_3_1_2.cpp例:8_3_1_3.cpp關於虛函數的一些說明一旦一個函數定義為虛函數,那麼無論它傳下多少層,都將保持為虛函數。虛函數必須是定義它的類的成員函數。虛函數與派生類中覆蓋它的函數有類型匹配,即返回類型、參數個數、類型都相同。虛函數的訪問控制規則由它聲明時的規則確定。基類的指針可以訪問派生類的函數,甚至是派生類的私有函數。8_3_1_5.cpp構造函數不能為虛函數,析構函數可以定義為虛函數。8_3_1_6.cpp含有虛函數的類的實例。基類的構造函數先於派生類的構造函數調用,在對象構造出來之前,派生類中定義的虛函數不可被該類的對象啟動。8_3_1_7.cpp純虛函數:在第一次聲明時不提供定義,例如classA{…;virtualvoidf()=0;…};抽象類:一個類如果至少有一個純虛函數就稱為抽象類。抽象類不能實例化,即它不能建立對象。8_3_1_8.cpp8.3.2實例有限狀態機:8_3_2_1.cpp定義一個parent類,其他狀態定義為parent的子類。指向子類的parent類的指針可以訪問子類的轉換函數。8_3_2_2.cpp8_3_2_3.cpp作業

一個三口之家,大家都知道父親會開車、母親會唱歌。但是父親還會修電視機,只有家裏人知道。小孩既會開車又會唱歌又會修電視機。母親瞞著任何人在外面做小工補貼家用。此外

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论