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

下载本文档

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

文档简介

面向對象的設計方法面向對象的C++程式設計基礎21.1面向對象的思想一、面向對象的含義

“面向對象”是軟體設計的一種新思想,旨在使人們分析、設計系統的方法更接近認識系統的方法;

面向對象方法就是為電腦軟體的創建提出了一種模型化世界的抽象方法;軟體工程專家給出了面向對象的描述:

面向對象

=對象

+分類

+繼承

+消息通信

即面向對象就是使用對象、類、繼承等機制,對象之間僅能通過消息的傳遞實現通信。3

二、面向對象的程式設計

面向過程的程式設計

基本思想:模組分解和功能抽象,複雜的程式必然包含一組數據以及用來處理這些數據的函數,但函數是獨立的。程式自身不清楚哪些函數處理了這些數據,即數據與處理這些數據的操作相分離。缺點是:1、程式修改麻煩:例如程式修改了一個變數名,則要修改所有使用該變數的語句;2、可靠性差,一致性難以保證:數據沒有封裝,數據可能被分散於程式各處的函數改變,數據從整體上很難保證可靠和一致。

面向對象的思想4

面向對象的程式設計

基本思想:將客觀世界抽象為多個對象,將要設計的系統表示為對象的集合;對同類對象抽象出其共性,形成類;類是封裝了“數據和處理這些數據的操作”的一個整體,對象是類的實例;類通過外部介面與外界聯繫,對象之間通過消息進行通訊。

類和對象是實現數據封裝的具體機制,通過這種機制,把數據以及與其相關的操作進行封裝(或捆綁),外界不能隨意修改和任意使用這些量,只有滿足一定的訪問許可權才能進行訪問操作,增強了數據的安全性(解決了數據與操作相分離)。二、面向對象的程式設計面向對象的思想5面向對象的基本概念

——對象一般意義上的對象:是現實世界中一個實際存在的事物。可以是有形的(比如一輛汽車),也可以是無形的(比如一項計畫)。是構成世界的一個獨立單位,具有:靜態特徵:可以用某種數據來描述動態特徵:對象所表現的行為或具有的功能6面向對象的基本概念

——對象面向對象方法中的對象:是系統中用來描述客觀事物的一個實體,它是用來構成系統的一個基本單位。對象由一組屬性和一組行為構成。屬性:用來描述對象靜態特徵的資料項目。行為:用來描述對象動態特徵的操作序列。7一、現實世界中的對象對象是現實世界的一個實體,它具有如下特徵:1、有一個名字以區別於其他對象;2、有一個狀態用來描述它的某些特徵;3、有一組操作,每一個操作決定了對象的一種功能或行為;對象的操作分為兩類:1)自身所承受的操作。2)是它施加於其他對象的操作。(例如人可以接受知識,人可以駕駛汽車)面向對象的基本概念8二、電腦世界中的對象在電腦世界中,可以把對象看成是記憶體中一個可標識的區域,它能保存固定或可變數目的數值(或數值的集合),這些數值代表對象的屬性數據和對象的成員函數代碼。從軟體形式上看,對象是系統程式員、應用程式員或用戶所定義的抽象數據類型的變數。面向對象的基本概念9對象的狀態指對象自身所具有的那些特徵(屬性);這些狀態的存在,使對象能對自身以及對外界對象施加操作;對象的狀態並不是完全用來直接為外界服務的,但它們本身是能夠為外界服務的基礎。

對象的狀態面向對象的基本概念10模組獨立性對象是獨立存在的模組,封裝了數據和操作。外部使用時只需瞭解它具有哪些功能。模組間的依賴性極小或幾乎沒有。動態連接性對象之間有聯繫,通過消息啟動機制,把一個個對象動態地連接在一起。易維護性對象修改、功能完善及實現的細節都被局限於對象的內部,不會涉及到外部。

對象的特性面向對象的基本概念11面向對象的基本概念

——類分類——人類通常的思維方法分類所依據的原則——抽象忽略事物的非本質特徵,只注意那些與當前目標有關的本質特徵,從而找出事物的共性,把具有共同性質的事物劃分為一類,得出一個抽象的概念。例如,石頭、樹木、汽車、房屋等都是人們在長期的生產和生活實踐中抽象出的概念。12面向對象的基本概念

——類面向對象方法中的"類"具有相同屬性和服務的一組對象的集合為屬於該類的全部對象提供了抽象的描述,包括屬性和行為兩個主要部分。類與對象的關係:

猶如模具與鑄件之間的關係,一個屬於某類的對象稱為該類的一個實例。面向對象的基本概念13

類與對象的關係類(範本)與對象(實例)的關係是抽象與具體的關係;同一類的不同實例之間,必有如下特點:相同的操作集合;相同的屬性集合;不同的對象名。面向對象的基本概念14

類的確定與描述類的確定採用歸納法,基於對所遇到對象的總體分析中,歸納出其共同的特徵來定義類;類是數據和對這些數據進行操作的函數的封裝體,它是一種同時含有數據和函數的構造數據類型(結構);類的描述同時包括數據和函數定義,類中的數據和函數稱為類的成員(數據成員、成員函數);數據成員是類的那些成員函數需要用到的變數,成員函數是對數據成員進行處理的程式段。面向對象的基本概念15面向對象的基本特性

——封裝性把對象的屬性和服務結合成一個獨立的系統單元。盡可能隱蔽對象的內部細節。對外形成一個邊界(或者說一道屏障),只保留有限的對外介面使之與外部發生聯繫。16

什麼是封裝性?在面向對象中,封裝是將一段程式代碼“包裝”起來,只需知道這段“代碼”完成的功能,而不必關心功能的實現細節;“代碼”包括一組數據和與這組數據相關的操作;封裝是指將一組數據(對象屬性)和與這組數據相關的操作(對象服務)集合在一起,形成一個不可分割、獨立的實體—對象,用戶不必知道對象行為的實現細節,只需根據對象提供的外部介面訪問對象的服務。面向對象的基本特性17

1.有一個清楚的邊界,對象的所有私有數據、內部程式(成員函數)細節都被限定在這個邊界內;

封裝應該具有以下幾個條件:2.至少有一個介面,這個介面描述了該與其它對象之間的相互作用、請求和回應,它就是消息;3.對象行為的內部實現代碼受封裝殼的保護,其他對象不能直接修改該對象所擁有的數據和相關程式代碼。面向對象的基本特性18

面向對象系統的封裝性

面向對象系統的封裝性是一種資訊隱藏技術。它的目的在於將對象的使用者與設計者分開,使用者不必知道對象行為實現的細節;

封裝機制提供了一種共用代碼的手段。通過封裝,把一段代碼定義在一個類中,並且在另一個類所定義的操作中,可以通過創建該類的實例,並向它發送消息而啟動這段程式代碼,達到共用代碼的目的。面向對象的基本特性19面向對象的基本特性

——繼承性繼承對於軟體複用有著重要意義,是面向對象技術能夠提高軟體開發效率的重要原因之一。定義:特殊類的對象擁有其一般類的全部屬性與服務,稱作特殊類對一般類的繼承。例如:將輪船作為一個一般類,客輪便是一個特殊類。201、繼承表達了對象之間的相交關係,即某類對象可以繼承另一類對象的特徵和能力。具有繼承關係的類有如下特徵:☆類間具有共用特徵(包括數據和程式代碼共用);☆類間具有細微的差別或新增部分(包括非共用的程式代碼和數據);☆類間具有層次結構(包含關係)。2、繼承的作用:在定義子類時不必重複在父類中定義的數據和操作,可減少代碼冗餘,提高軟體複用性;增強一致性,減少模組之間的介面和介面,易於程式維護。

繼承的含義面向對象的基本特性21

繼承的分類

從繼承源上可劃分為單繼承和多繼承;

單繼承:一個類只允許有一個父類時,這種類的繼承為單繼承;多繼承:一個類同時允許有2個以上的父類時,這種類的繼承為多繼承。面向對象的基本特性22

單繼承與多繼承ABCDE單繼承多繼承FEDCBA23

面向對象系統的繼承性能清晰體現相關類之間的層次結構關係;能減小代碼和數據的冗餘度,增加程式重用性;能通過增強一致性來減少模組間的介面和介面,增加程式的易維護性;繼承是能自動傳播代碼的有力工具;繼承還是在一些比較一般的類的基礎上進行構造、建立和擴充新類的最有效的手段,利於軟體設計的逐步細化,即先進行公共特性的設計,再自頂向下開發子類,逐步加入新內容。24面向對象的基本特性

——多態性多態是指在一般類中定義的屬性或行為,被特殊類繼承之後,可以具有不同的數據類型或表現出不同的行為。這使得同一個屬性或行為在一般類及其各個特殊類中具有不同的語義。例如:數的加法->實數的加法

->複數的加法25

多態性的含義多態性(Polymorphism)是指同一名字(函數、運算符)在不同的場合具有不同的語義,或者同一介面有多種實現;C++中的多態性是指不同的對象收到相同的消息時產生不同的動作或行為;C++支持兩種多態性:

1、編譯時的多態性:通過函數重載來實現。

2、運行時的多態性:通過虛函數來實現。面向對象的基本特性26

重載(Overloading)C++允許為已有的函數和運算符重新賦予新的含義,即具有相同名字的函數和運算符在不同的場合可以表現為不同的行為;重載的含義是指通過為函數和運算符創建附加定義而使它們的名字重載,即相同名字的函數或運算符在不同的場合可以表現出不同的功能;函數重載:同一個作用域內若干個參數特徵不同的函數可以使用相同的名字,定義重載函數時,函數名相同,函數參數類型、個數、順序必須不同;運算符重載:同一個運算符可以施加在兩個任意類型的運算元(例如結構變數或對象)上。27

虛函數虛函數是指在類等級的不同層次中說明的名字、參數特徵和返回值類型都相同但實現演算法不同的函數;虛函數使用戶在一個類等級中可以使用相同函數的多個版本,每個版本均屬於類等級中不同的類,究竟使用的是哪一個特定的版本需要在運行中決定;虛函數的各個版本中,其返回值、函數參數的個數和類型必須一致。28電腦程式電腦的工作是用程式來控制的程式是指令的集合。指令是電腦可以識別的命令。電腦語言的發展29機器語言與組合語言由電腦硬體系統可以識別的二進位指令組成的語言稱為機器語言。電腦發展的初期,軟體工程師們只能用機器語言來編寫程式。這一階段,在人類的自然語言和電腦編程語言之間存在著巨大的鴻溝。組合語言將機器指令映射為一些可以被人讀懂的助記符,如ADD、SUB等。此時編程語言與人類自然語言間的鴻溝略有縮小,但仍與人類的思維相差甚遠。因為它的抽象層次太低,程式員需要考慮大量的機器細節。電腦語言的發展30高級語言高級語言遮罩了機器的細節,提高了語言的抽象層次,程式中可以採用具有一定涵義的數據命名和容易理解的執行語句。這使得在書寫程式時可以聯繫到程式所描述的具體事物。電腦語言的發展31面向對象的語言出發點:更直接地描述客觀世界中存在的事物(對象)以及它們之間的關係。特點:是高級語言。將客觀事物看作具有屬性和行為的對象。通過抽象找出同一類對象的共同屬性和行為,形成類。通過類的繼承與多態實現代碼重用。電腦語言的發展32面向對象的語言優點:使程式能夠比較直接地反問題域的本來面目,軟體開發人員能夠利用人類認識事物所採用的一般思維方法來進行軟體開發。電腦語言的發展33

LISP語言:以表處理為特色,是一種人工智慧語言。

Simula67語言:引入了幾個面向對象程式設計語言中的重要概念和特性,即數據抽象、類機構和繼承機制。

SmallTalk語言:源於Simula語言,體現了純粹的面向對象程式設計思想,是真正的面向對象語言。

C++語言:1980年AT&T設計了混合型的面向對象程式設計語言C++,在C的基礎上擴展了類、對象等機制,並相容C語言,應用最為廣泛。面向對象的語言電腦語言的發展34程式設計方法的發展歷程

——面向過程的程式設計方法程式的目的:用於數學計算主要工作:設計求解問題的過程缺點:對於龐大、複雜的程式難以開發和維護35程式設計方法的發展歷程

——面向過程的結構化程式設計方法設計思路自頂向下、逐步求精。採用模組分解與功能抽象,自頂向下、分而治之。程式結構:按功能劃分為若干個基本模組,形成一個樹狀結構。各模組間的關係盡可能簡單,功能上相對獨立;每一模組內部均是由順序、選擇和迴圈三種基本結構組成。其模組化實現的具體方法是使用副程式。36程式設計方法的發展歷程

——面向過程的結構化程式設計方法優點:有效地將一個較複雜的程式系統設計任務分解成許多易於控制和處理的子任務,便於開發和維護。面向對象的方法37程式設計方法的發展歷程

——面向過程的結構化程式設計方法缺點:可重用性差、數據安全性差、難以開發大型軟體和圖形介面的應用軟體把數據和處理數據的過程分離為相互獨立的實體。當數據結構改變時,所有相關的處理過程都要進行相應的修改。每一種相對於老問題的新方法都要帶來額外的開銷。圖形用戶介面的應用程式,很難用過程來描述和實現,開發和維護也都很困難。38程式設計方法的發展歷程

——面向對象的方法將數據及對數據的操作方法封裝在一起,作為一個相互依存、不可分離的整體——對象。對同類型對象抽象出其共性,形成類。類通過一個簡單的外部介面,與外界發生關係。對象與對象之間通過消息進行通訊。39程式設計方法的發展歷程

——面向對象的方法優點:程式模組間的關係更為簡單,程式模組的獨立性、數據的安全性就有了良好的保障。通過繼承與多態性,可以大大提高程式的可重用性,使得軟體的開發和維護都更為方便。40面向對象的軟體工程面向對象的軟體工程是面向對象方法在軟體工程領域的全面應用。它包括:面向對象的分析(OOA)面向對象的設計(OOD)面向對象的編程(OOP)面向對象的測試(OOT)面向對象的軟體維護(OOSM)面向對象的軟體開發41系統分析系統分析階段應該扼要精確地抽象出系統必須做什麼,但是不關心如何去實現。面向對象的系統分析,直接用問題域中客觀存在的事物建立模型中的對象,對單個事物及事物之間的關係,都保留他們的原貌,不做轉換,也不打破原有界限而重新組合,因此能夠很好地映射客觀事物。面向對象的軟體開發42設計針對系統的一個具體實現運用面向對象的方法。其中包括兩方面的工作:把OOA模型直接搬到OOD,作為OOD的一部分針對具體實現中的人機介面、數據存儲、任務管理等因素補充一些與實現有關的部分。面向對象的軟體開發43編程OOP工作就是用一種面向對象的編程語言把OOD模型中的每個成份書寫出來,是面向對象的軟體開發最終落實的重要階段。面向對象的軟體開發44測試測試的任務是發現軟體中的錯誤。在面向對象的軟體測試中繼續運用面向對象的概念與原則來組織測試,以對象的類作為基本測試單位,可以更準確的發現程式錯誤並提高測試效率。面向對象的軟體開發45維護將軟體交付使用後,工作並沒有完結,還要根據軟體的運行情況和用戶的需求,不斷改進系統。使用面向對象的方法開發的軟體,其程式與問題域是一致的,因此,在維護階段運用面向對象的方法可以大大提高軟體維護的效率。面向對象的軟體開發46C++語言的產生C++是從C語言發展演變而來的,首先是一個更好的C引入了類的機制,最初的C++被稱為“帶類的C”1983年正式取名為C++從1989年開始C++語言的標準化工作於1994年制定了ANSIC++標準草案於1998年11月被國際標準化組織(ISO)批准為國際標準,成為目前的C++C++的初步知識47C++的特點全面相容C它保持了C的簡潔、高效和接近組合語言等特點對C的類型系統進行了改革和擴充C++也支持面向過程的程式設計,不是一個純正的面向對象的語言支持面向對象的方法C++的初步知識48從C到C++最簡單的C++程式C++程式的構成和書寫格式C++程式的編寫和實現C++(Cplusplus)是C語言的超集,完全相容C語言,但在概念上不同於C,應按C++自己的方式來使用它,掌握C++的思維方式、程式設計方法和編程習慣。那麼,C++對C做了哪些修改和增強?C++的初步知識49函數原形說明變數的說明輸入輸出const說明符void類型從C到C++C++的初步知識50

函數原形說明C++要求為函數提供完全的原型,包括所有參數的類型和返回值類型,目的在於:編譯系統可以對函數的定義和使用之間的一致性進行嚴格的檢查,保證函數使用的正確性;在函數定義和聲明時,必須提供全部資訊:

voiddisplay(int,char*,float);intmixture(int,float,char*);C++的初步知識51

變數的說明在C中,變數的定義必須出現在函數或複合語句的最前面,在正常執行語句後面不能再定義變數。intm,n,k;m=10;n=9;k=m*n;….在C++中,變數的定義可以出現在任何位置。intm,n,k;m=10;n=9;k=m*n;….intx,y;y=k+m;…C++的初步知識52

輸入和輸出C++中除了保留C標準庫中的各種輸入和輸出函數外,還提供了一套新的輸入和輸出函數—流式輸入輸出。使用時包含頭檔“iostream.h”。例:

#include<iostream.h>intx,y;floatz;cin>>x>>y>>z;//從標準終端輸入數據

char*str=“Hello,howareyou!”;cout<<“Pleaseoutputtheinfoofthestring:”<<str<<“\n”;//向螢幕輸出字串53

const說明符定義常量時,C語言用#define,而C++用const說明符,const在C++中的作用:1.代替#define宏定義常量例:#defineMAX100

可替代為:

constintMAX=100;或intconstMAX=100;2.定義常量數組

constfloatdata[]={1.2,2.5,3.6,4.8,5.5};C++的初步知識54

const說明符3.

const說明符與函數參數相連接。例:voidprint_value(constintvalue){cout<<value;}

試圖在該函數體中改變const參量value的是非法的。C++的初步知識55

const說明符4.定義指針常量,根據const位置的不同含義也不同,有三種方式:(1)指向常量的指針:說明一個指針變數指向的數據是常量。(name是指向字串常量的指針,name指向的字串不能更改,但name可以更新)

const

char*name=“Richard”;name=“Martin”;對

name[0]=‘C’;錯C++的初步知識56

const說明符(2)常指針:把指針本身聲明為一個常量,而不是將它指向的對象聲明為常量。(name不能更改,name指向的內容可更新)

char*constname=“Richard”;name=“Martin”;錯

name[0]=‘C’;對(3)指向常量的常指針:

這個指針本身不能改變,它指向的值也不能改變。(name不能更改,name指向的內容也不能更新)

constchar*constname=“Richard”;name=“Martin”;錯

name[0]=‘C’;錯57

void類型void是指沒有數值的數據類型,沒有任何返回值的函數應說明為void類型。例如:voidfun(int*);void也可表示一個函數不需要任何入口參數。例如:intgraph(void);將C程式轉換成與C++相容的最常見的工作就是將沒有返回值的函數說明為void類型。C++嚴格檢查所有的函數原型是否包括:返回值類型、函數名和各個參數的類型。C++的初步知識58例1.4.1輸出一行字元:“ThisisaC++program.”程式如下:#include<iostream>//用cout輸出時需要用此頭檔usingnamespacestd;//使用命名空間std

intmain(){

cout<<“ThisisaC++program.\n”;//用C++的

//方法輸出一行資訊

return0;}程式運行時輸出:ThisisaC++program.最簡單的C++程式#include<iostream.h>59命名空間(Namespace)一個命名空間將不同的識別字集合在一個命名作用域(namedscope)內為了解決命名衝突例如,聲明一個命名空間NS:namspaceNS{classFile;voidFun();}

則引用識別字的方式如下,NS::Fileobj;NS::Fun();沒有聲明命名空間的識別字都處於無名的命名空間中60命名空間(Namespace)可以用using來指定命名空間例如,經過以下聲明:

usingNS::File;

在當前作用域中就可以直接引用Fileusingnamespacestd;

命名空間std中所有識別字都可直接引用在新的C++標準程式庫中,所有識別字都聲明在命名空間std中,頭檔都不使用擴展名61最簡單的C++程式例1.4.2求a、b兩個數之和。//求兩個數之和(本行是注釋)#include<iostream>//用cout輸出時需要用此頭檔usingnamespacestd;//使用命名空間std

intmain()//主函數首部{inta,b,sum;//定義變數

cin>>a>>b;//輸入語句

sum=a+b;

cout<<“a+b=”<<sum<<endl;//輸出語句

return0;}注:1825(輸入18和25給a、b),a、b之間一個空格62C++程式的書寫格式一個C++程式可以由一個程式單位或多個程式單位構成。每一個程式單位作為一個檔,每個檔由若干個函數組成。由函數構成的C++程式中,必須只有一個主函數main(),它是程式執行的入口。需要指出兩點:1、C++函數(包括main)的定義和聲明,必須提供函數的全部資訊:返回值、函數參數類型和個數。無返回值或無參的情況用void;2、注釋形式:在一行語句內,“//”後面的字元被視為注釋在多行語句內,“/*”和“*/”中間的所有字元被視為注釋。63C++程式的編寫和實現用C++語言編寫根源程式*.cpp;對根源程式進行編譯,形成*.obj檔。如果編譯出錯,再修改根源程式,直到編譯正確;將目標檔與C++編譯器提供的庫檔進行連接,形成可執行的二進位檔*.exe;運行程式;分析運行結果。642.1類的聲明和對象定義C++類及其對象的封裝性類是具有相同屬性和行為的一組對象的集合,它為屬於該類的全部對象提供了統一的抽象描述,其內部包括屬性和行為兩個主要部分。利用類可以實現數據的封裝、隱藏、繼承與派生。利用類易於編寫大型複雜程式,其模組化程度比C中採用函數更高。652.1類的聲明和對象定義C++類及其對象的封裝性類是對象共性特徵的抽象,對象的類型稱為類,類是對象的範本,對象是類的具體實例;先聲明一個類,再定義對象,類是抽象的,不佔用記憶體,對象是具體的,佔用實際的存儲空間;可以看作是一種特殊的構造數據類型,是結構體的擴充形式;類是數據和對這些數據進行操作的函數的封裝體,是包括數據和函數的數據類型;類的定義包括數據和函數的定義,類中的數據和函數都是類的成員;在C++中,類用class來構造。66類的聲明

//聲明結構體類型struct

Student{intnum;

charname[20];

charsex;

};//定義2個結構變數Studentstud1,stud2;class

Student//聲明類,以class開頭

{intnum;

charname[20];

charsex;//以上3行是數據成員

voiddisplay()//成員函數

{cout<<“num:”<<num<<endl;

cout<<“name:”<<name<<endl;

cout<<“sex:”<<sex<<endl;}};

//定義Student類的對象stud1,stud2Student

stud1,stud2;672.1類的聲明和對象定義上述類定義中未限定成員的訪問屬性,對象stud1的數據和函數都是private的,數據安全了。但外界不能調用stud1中的函數和功能,因為沒有提供類的對外的介面,類有何用?不能把類中的全部成員與外界隔離,一般將類中的數據隱藏起來,聲明為私有的(private),把成員函數作為對外界的介面,聲明為公有的(public)。例如,上述類聲明改為:classStudent//聲明類類型{private://聲明以下部分為私有

intnum;

charname[20];

charsex;

public://聲明以下部分為公有

voiddisplay(){cout<<“num:”<<num<<endl;

cout<<“name:”<<name<<endl;

cout<<“sex:”<<sex<<endl;}};Student

stud1,stud2;68在C++中,定義類的一般格式為:class

類名{

private:

//私有類型只限於通過自己的成員函數

//來訪問,即只有類本身能夠訪問它數據成員和成員函數說明

public:

//公有類型提供了類的外部介面,允許類

//的使用者來訪問它數據成員和成員函數說明

protected:

//保護類型只允許本類成員函數或派生

//類成員函數訪問,用於類的繼承和派生數據成員和成員函數};69公有類型成員在關鍵字public後面聲明,它們是類與外部的介面,任何外部函數都可以訪問公有類型數據和函數。類的聲明和對象的定義70私有類型成員在關鍵字private後面聲明,只允許本類中的函數訪問,而類外部的任何函數都不能訪問。如果緊跟在類名稱的後面聲明私有成員,則關鍵字private可以省略。類的聲明和對象的定義71保護類型與private類似,其差別表現在繼承與派生時對派生類的影響不同。類的聲明和對象的定義72在類的定義中應注意以下幾點:1、“類名”是一個合法的識別字;2、關鍵字private,public和protected說明類成員的三種訪問許可權;3、{}以內的部分是“類內”,{}以外的部分為“類外”;4、類定義的聲明部分在“類內”,類的成員函數既可以在“類內”定義,也可以在“類外”定義;5、在“類內”不允許對所聲明的數據成員進行初始化,類的數據成員的類型可以任意。73classCArea//聲明一個類{private://私有部分

intx,y,area;public://公有部分

voidsquarea(intvx,intvy);};例題2.1.174類的成員classClock{public:

voidSetTime(intNewH,intNewM,

intNewS);

voidShowTime();private:intHour,Minute,Second;};成員數據成員函數類的聲明和對象的定義75voidClock::SetTime(intNewH,intNewM,

intNewS){Hour=NewH;Minute=NewM;Second=NewS;}voidClock::ShowTime(){cout<<Hour<<":"<<Minute<<":"<<Second;}類的聲明和對象的定義76數據成員與一般的變數聲明相同,但需要將它放在類的聲明體中。類的聲明和對象的定義77成員函數在類中說明原形,可以在類外給出函數體實現,並在函數名前使用類名加以限定。也可以直接在類中給出函數體,形成內置成員函數。允許聲明重載函數和帶默認形參值的函數類的聲明和對象的定義78類和結構體的異同1、均為構造類型;2、結構體用struct、類用class作為標識;2、結構體中的成員只有數據成員,且訪問許可權默認為public的;3、類的成員包括數據和函數,且訪問許可權可以設置為private、public和protected的;4、結構沒有實現數據封裝,數據可以被任何外部函數訪問。類實現了數據封裝,可以將數據限定為只能被本身的成員函數訪問。類的聲明和對象的定義79定義對象的方法1、先聲明類類型,然後再定義對象:如Student

stud1,stud2;在聲明類類型之後,定義對象有2種方法:class類名對象名;如classStudentstud1,stud2;類名對象名;如Student

stud1,stud2;類的聲明和對象的定義80定義對象的方法2、在聲明類類型的同時定義對象:classStudent

//聲明類類型{public://先聲明公用部分

voiddisplay()

{cout<<“num:”<<num<<endl;

cout<<“name:”<<name<<endl;

cout<<“sex:”<<sex<<endl;}

private://後聲明私有部分

intnum;

charname[20];

charsex;}stud1,stud2;//定義Student類的對象stud1,stud2類的聲明和對象的定義81定義對象的方法3、不出現類名,直接定義對象:class

//聲明類類型{public://聲明公用部分

……

private://聲明私有部分

……

protected://聲明保護部分

……}stud1,stud2;//定義對象stud1,stud2

定義多個對象時,對象名之間用逗號隔開;對象名可以是一般的對象、指向對象的指針或引用名,也可以是對象數組。

類的聲明和對象的定義82例2.1.2定義一個日期類CDate,再創建一個生日對象。classCDate{intyear;

intmonth;

intday;public:

voidSetDate(int,int,int);

voidShowDate();}myBirthday;//同時創建對象myBirthday或者定義類之後:CDate

myBirthday,*p,q[5];類的聲明和對象的定義83

2.2

類的成員函數C++類及其對象的封裝性類的成員函數具有一般函數的性質,它同時屬於某個類的成員,出現在類定義體中,可被限定為具有private、public和protected三種訪問屬性;成員函數可以訪問本類中的任何成員(包括private和public特性),可以引用在本作用域中有效的數據;private屬性的成員函數只能被本類其他的成員函數調用,不能被外界調用;public屬性的成員函數可以被外界調用,它是類的對外介面。84在類外定義成員函數類的成員函數類的成員函數可以在“類內”聲明,在“類外”定義;類外定義成員函數的一般形式如下:

返回值類型

類名::成員函數名(參數表){…

…//函數體

}

其中::是作用域運算符。85例2.2.1classStudent

{public:

voiddisplay();//公用成員函數原型聲明

private:

intnum;

stringname;

charsex;//以上3行是私有數據成員};voidStudent

::display()//在類外定義成員函數{cout<<“num:”<<num<<endl;

cout<<“name:”<<name<<endl;

cout<<“sex:”<<sex<<endl;}Student

stud1,stud2;//定義2個類對象類的成員函數86內置(inline)成員函數有些簡單的成員函數可以直接在類定義中定義,在類定義體中定義的成員函數稱為內置函數(內聯函數);內置函數可以減少函數調用時的記憶體開銷,不用記錄函數調用返回地址,只將代碼嵌入到函數調用點。內置函數的定義有兩種方法:1、隱式定義將成員函數的定義體放在“類內”中。2、顯式定義在“類內”聲明,在“類外”定義時在函數名前加關鍵字inline。類的成員函數87內置成員函數舉例(一)classPoint{public:voidInit(intinitX,intinitY)

{X=initX;Y=initY;}intGetX(){returnX;}intGetY(){returnY;}private:intX,Y;};類的成員函數88內置成員函數舉例(二)classPoint{public:voidInit(intinitX,intinitY);intGetX();

intGetY();

private:intX,Y;};類的成員函數inlinevoidPoint::

Init(intinitX,intinitY){X=initX;Y=initY;}inlineintPoint::GetX(){returnX;}inlineintPoint::GetY(){returnY;}90成員函數的存儲方式定義類對象時,系統會為每個對象分配存儲空間,包括為類對象的數據和函數代碼分配空間;如果定義同類的10個對象,那麼如何為這10個對象分配不同的空間?10個同類對象佔用存儲單元的情況類的成員函數91成員函數的存儲方式為了節約記憶體,只用一段存儲空間來存放10個對象擁有的共同的函數代碼段,如下圖:

10個同類對象成員函數的存儲方式C++規定:對象佔用的存儲空間只是對象數據成員佔用的存儲空間,可用sizeof函數驗證;共同的成員函數代碼存儲在對象空間之外。類的成員函數92成員函數的存儲方式調用不同對象的成員函數時都是執行同一段函數代碼,但其執行結果一般不同(常與數據有關);不同對象使用同一段函數代碼,它們如何對不同對象中的數據進行操作呢?C++專門為此設計了一個this指針,用來指向不同的對象;調用哪個對象,this就指向哪個對象,就訪問它的成員。類的成員函數93類中成員的訪問方式類中成員互訪直接使用成員名類外訪問使用“對象名.成員名”方式訪問

public

屬性的成員類的成員函數94例:類的應用舉例#include<iostream>usingnamespacestd;classClock{//類的聲明略}//類的實現略voidmain(void){ClockmyClock;

myClock.SetTime(8,30,30);

myClock.ShowTime();}類的成員函數95對象成員的引用訪問對象中的成員有3種方法:1、通過對象名和成員運算符訪問對象中的成員,即:

對象名.數據成員名

or對象名.成員函數名(參數表)例如:stud1.num=1001;

stud1.display();

//設num和display函數為public成員

類的成員函數96對象成員的引用定義一個日期類,使其具有輸出當前日期的功能。見p-27例2.3.1:引用對象的成員2、通過指向對象的指針訪問對象中的成員,即:對象指針->數據成員名

or對象指針->成員函數名(參數表)

例如:Timet,*p=&t;cout<<p->hour;//hour是t中的成員3、通過對象的引用變數訪問對象中的成員。類的成員函數97類的封裝性類將一組數據和操作這些數據的演算法封裝在自定義的抽象數據類型中。一般將類的所有數據聲明為private(與外界隔離),將成員函數聲明為public(外界可以調用),外界通過調用公用成員函數實現對數據的操作;公用成員函數是用戶使用類的公用介面(publicinterface),用戶只需知道如何調用公用成員函數,不需瞭解函數的內部實現細節,此即介面與實現分離;通過成員函數對數據成員進行操作稱為類的實現。為了防止用戶隨意修改公用成員函數,一般不向用戶公開公用成員函數的源代碼,用戶只能接觸到其目標代碼;類中被操作的數據是私有的,實現的細節對用戶隱蔽,此即私有實現(privateimplementation)。“類的公用介面與私有實現的分離”形成了資訊隱蔽。

類的封裝和資訊隱藏98封裝性的好處軟體工程的一個最基本的原則就是將介面與實現分離,資訊隱蔽是軟體工程的重要概念,其好處在於:(1)如果想修改或擴充類的功能,只需修改本類中有關的數據成員和與它有關的成員函數,程式中類外的部分可以不必修改。(2)如果在編譯時發現類中的數據讀寫有錯,不必檢查整個程式,只需檢查本類中訪問這些數據的少數成員函數。這樣,就極大方便了程式(特別是大程式)的設計、修改和調試。類的封裝和資訊隱藏99類聲明和成員函數定義的分離類被一個程式使用,將類的聲明和成員函數的定義寫在檔開頭;類被多個程式使用,需要重複將其寫在多個檔開頭;將類的聲明(包含成員函數的聲明)放在指定的頭檔中,用戶使用類時,只要包含相應的頭檔,即可定義該類的對象、調用對象的公用成員函數;為了實現資訊隱蔽,將類的成員函數定義放在另一個檔中。這時,一個程式有兩個模組:類的成員函數定義檔student.cpp和主模組main.cpp,它們都包含類聲明頭檔student.h;將student.cpp編譯成目標檔student.obj,形成用戶類庫,與main.obj和系統資源庫鏈接而成main.exe。類的封裝和資訊隱藏100類聲明和成員函數定義的分離//student.hclassStudent{public:

voiddisplay();

private:

intnum;

charname[20];

charsex;};類的封裝和資訊隱藏101類聲明和成員函數定義的分離//student.cpp#include<iostream.h>#include“student.h”voidStudent::display()

{cout<<“num:”<<num<<endl;cout<<“name:”<<name<<endl;cout<<“sex:”<<sex<<endl;}//main.cpp#include<iostream.h>#include“student.h”intmain(){Student

stud;

stud.Display();

return0;}類的封裝和資訊隱藏102類聲明和成員函數定義的分離圖2.4.1包含多個原始檔案程式的編譯和連接過程類的封裝和資訊隱藏103類聲明和成員函數定義的分離使用類庫將減少用戶對類和成員函數定義的工作量;類庫包括兩個部分:(1)類聲明頭檔;(2)已經編譯過的成員函數定義檔-目標檔;用戶只需將類庫裝入到自己的電腦系統(裝在C++編譯系統所在的子目錄),並在程式中用#include命令將有關類聲明的頭檔包含到程式中,即可使用這些類和其中的成員函數了;介面與實現的分離,為軟體開發商給用戶提供類庫創造了條件,而類實現的程式代碼得到了保護。類的封裝和資訊隱藏104構造函數構造函數的作用是在對象被創建時使用特定的值構造對象,或者說將對象初始化為一個特定的狀態。在對象創建時由系統自動調用。如果程式中未聲明,則系統自動產生出一個默認形式的構造函數允許為內置函數、重載函數、帶默認形參值的函數構造函數和析構函數105構造函數構造函數和析構函數構造函數的名字必須與類名相同;構造函數一般聲明為public,無返回值,無需定義返回類型;構造函數是系統自動調用的,且執行一次;構造函數不能被繼承,但允許重載(overloading);構造函數的功能是對對象進行初始化,一般構造函數用於對象的初始化,每當對象被聲明時對數據成員做初始化,不做賦值外的事情。106構造函數的幾種形式構造函數和析構函數構造函數可為內聯函數,可以為無參數或帶參數,還可以缺省參數,例如:無參的構造函數參數化的構造函數缺省參數的構造函數多構造函數拷貝構造函數107classCArea{public:CArea(){x=0;y=0;}//無參數的構造函數

CArea(intrx,intry=0);//帶缺省參數的構造函數

CArea(floatrr){rr=0;}//帶一個參數的構造函數

CArea(floatrr,char*ra);//帶兩個參數的構造函數

};例2.5.1在類中定義構造函數,見p33在類中聲明的多種構造函數:例108構造函數舉例classClock{public:

Clock(intNewH,intNewM,intNewS);//構造函數

voidSetTime(intNewH,intNewM,intNewS); voidShowTime();private: intHour,Minute,Second;};構造函數和析構函數構造函數的實現:Clock::Clock(intNewH,intNewM,intNewS){ Hour=NewH; Minute=NewM; Second=NewS;}建立對象時構造函數的作用:voidmain(){

Clockc(0,0,0);//隱含調用構造函數,將初始值作為實參。

c.ShowTime();}31110

構造函數的使用何時調用構造函數?在類對象進入其作用域時調用構造函數;構造函數沒有返回值,不要在定義構造函數時聲明類型;構造函數不需要用戶調用,也不能被用戶調用;在構造函數體中,不僅可以對數據成員賦初值,還可以包含其他語句如cout;如果用戶沒有定義構造函數,C++系統會自動生成一個構造函數,其函數體為空,不執行初始化操作;要想初始化一個對象,需要重新定義構造函數,否則對象的狀態將是隨機的。構造函數和析構函數111帶參數的構造函數定義對象時,通過不同參數值的傳遞實現不同對象的不同初始化,可以使用帶參數的構造函數;一般格式:構造函數名(類型1形參1,類型2形參2,……)用戶不能顯式地調用構造函數,也無法採用常規的調用函數的方法給出實參(如fun(a,b))。實參只能在定義對象時給出,定義對象的一般格式:類名對象名(實參1,實參2,……);例2.5.2:有兩個長方體,長、寬、高分別為:(1)12,25,30;(2)15,30,21。用帶參數的構造函數編寫程式求其體積。構造函數和析構函數112使用參數初始化表

在定義對象時,可使用參數初始化表來實現對數據成員的初始化,在函數首部實現:Box::Box(inth,intw,intlen):height(h),width(w),length(len){}

其含義是:用形參h的值初始化數據成員height,用形參w的值初始化數據成員width,用形參len的值初始化數據成員length。構造函數和析構函數113構造函數的重載

一個類可以定義多個構造函數,使用戶選用不同的方式完成對象數據的初始化;重載的所有構造函數同名,但其參數類型、參數個數必須有所區別。構造函數和析構函數114例2.5.3

在例2.5.2的基礎上定義兩個構造函數,其中一個無參數,一個有參數,見p37

重載構造函數的例子例,可以在類中聲明的多種構造函數:classCArea{public:CArea(){x=0;y=0;}//無參數的構造函數

CArea(intrx,intry=0);//帶缺省參數的構造函數

CArea(floatrr){rr=0;}//帶一個參數的構造函數

CArea(floatrr,char*ra);//帶兩個參數的構造函數

};115

缺省構造函數在調用構造函數時不必給出實參的構造函數,稱為默認構造函數(DefaultConstructor)或缺省構造函數;無參數的構造函數屬於缺省構造函數;如果在定義對象時選用無參構造函數,應按以下形式定義對象:

Boxbox1;//調用無參構造函數建立對象在一個類中可以包含多個構造函數,但是在創建每個對象時,只執行其中一個匹配版本的構造函數。構造函數和析構函數116默認形參值的作用函數在聲明時可以預先給出默認的形參值,調用時如給出實參,則採用實參值,否則採用預先給出的默認形參值。例如:intadd(intx=5,inty=6){returnx+y;}voidmain(void){add(10,20);//10+20add(10);//10+6add();//5+6}117默認形參值的說明次序默認形參值必須從右向左順序聲明,並且在默認形參值的右面不能有非默認形參值的參數。因為調用時實參取代形參是從左向右的順序。例:intadd(intx,inty=5,intz=6);//正確intadd(intx=1,inty=5,intz);//錯誤intadd(intx=1,inty,intz=6);//錯誤118默認形參值與函數的調用位置調用出現在函數體實現之前時,默認形參值必須在函數原形中給出;而當調用出現在函數體實現之後時,默認形參值需在函數實現時給出。例:intadd(intx=5,inty=6);voidmain(void){add();

//調用在實現前}intadd(intx,inty){returnx+y;}intadd(intx=5,inty=6){returnx+y;}voidmain(void){add();

//調用在實現後}119默認形參值的作用域在相同的作用域內,默認形參值的說明應保持唯一,但如果在不同的作用域內,允許說明不同的默認形參。例:intadd(intx=1,inty=2);voidmain(void){intadd(intx=3,inty=4);add();//使用局部默認形參值(實現3+4)}voidfun(void){...

add();//使用全局默認形參值(實現1+2)}120

使用默認參數的構造函數使用默認參數的構造函數,即構造函數的參數表中沒有參數;如果創建對象時不需要通過傳遞參數來初始化對象,可以使用它。例2.5.4:將例2.5.3的構造函數改為含默認值參數值,長、寬、高的默認值均為10。構造函數和析構函數121

使用默認參數的構造函數注意:在構造函數中使用默認參數提供了建立對象的多種初始化方法,相當於多個重載的構造函數;應該在聲明構造函數時指定參數的默認值,而不能只在定義構造函數時指定默認值;如果構造函數的全部參數都指定了默認值,則在定義對象時可以不給出,或給出一個、幾個實參;在一個類中定義了全部默認參數的構造函數後,不能再定義重載構造函數,否則會出現二義性。Box(int=10,int=10,int=10);//指定全部參數為默認參數Box();

//聲明無參構造函數,是重載構造函數Box(int,int);

//聲明有2個參數的構造函數若有以下語句:Boxbox1;

//無法確定調用第1個、還是第2個構造函數?Boxbox2(15,30);

//無法確定調用第1個、還是第3個構造函數?例2.5.5。

析構函數(destructor)也是一個特殊的成員函數,它的作用與構造函數相反.它的名字是類名的前面加一個“~”符號。在C++中“~”是位取反運算符,從這點也可以想到:析構函數是與構造函數作用相反的函數。當對象的生命期結束時,會自動執行析構函數。比如說如果在一個函數中定義了一個對象(它是自動局部對象),當這個函數被調用結束時,對象應該釋放,在對象釋放前自動執行析構函數。析構函數析構函數的作用並不是刪除對象,而是在撤銷對象佔用的記憶體之前完成一些清理工作。最典型的情況是構造對象時,在構造函數中分配了資源,例如動態申請了一些記憶體單元,在對象消失時就要釋放這些記憶體單元。一般由一系列的delete組成。析構函數不返回任何值,沒有函數類型,也沒有函數參數。因此它不能被重載。一個類可以有多個構造函數,但只能有一個析構函數。析構函數一般情況下,類的設計者應當在聲明類的同時定義析構函數,以指定如何完成“清理”的工作。如果用戶沒有定義析構函數,C++編譯系統會自動生成一個析構函數,但它只是徒有析構函數的名稱和形式,實際上什麼操作都不進行。想讓析構函數完成任何工作,都必須在定義的析構函數中指定。析構函數125析構函數析構函數的作用與構造函數相反。析構函數的特點:(1)析構函數不能接受任何參數,也沒有返回類型說明;(2)一個類只有一個析構函數,如果用戶未編寫析構函數,編譯系統會自動生成一個缺省的析構函數,此函數不做任何事情;(3)析構函數不能重載。構造函數和析構函數126何時執行析構函數?(1)一個函數中定義的對象(自動局部的),在這個函數結束調用時,對象應該釋放,並在對象釋放前自動執行析構函數;(2)static類型的局部對象在函數調用結束時並不釋放,也不調用析構函數,只在main函數結束或調用exit函數結束程式時,才調用static局部對象的析構函數;(3)一個全局對象,在程式離開其作用域時(如main函數結束或調用exit函數),調用該全局對象的析構函數;(4)用new運算符動態建立的對象,當用delete運算符釋放該對象時,先調用該對象的析構函數;(5)如果用戶沒定義析構函數,C++編譯系統會自動生成一個析構函數,只是它實際上不執行任何操作。127構造函數和析構函數共同點都沒有返回值,無需指出返回類型;不能被繼承;構造函數可以有缺省參數;不能用常規調用方法調用構造函數;當使用完全的限定名(包括對象名、類名、函數名)時可以調用析構函數;定義對象時,編譯程序自動調用構造函數,刪除對象時,編譯程序自動調用析構函數。構造函數和析構函數128

構造函數和析構函數的調用順序調用析構函數的次序正好與調用構造函數的次序相反,最先被調用的構造函數,其對應的(同一對象中的)析構函數最後被調用,而最後被調用的構造函數,其對應的析構函數最先被調用;“先構造的後析構、後構造的先析構”的先進後出的特徵。構造函數和析構函數129圖2.7.1構造函數與析構函數調用順序調用構造函數和析構函數的順序構造函數和析構函數

例2.6.1

包含構造函數和析構函數的C++程式。130

指向對象的指針對象存儲空間的起始地址叫對象指針;可以定義一個指針變數,存放對象空間的起始地址,如:

Timet1;//創建Time類對象t1Time*pt=&t1;//定義指向Time類對象

//的指針pt,並將t1的起始地址賦給pt對象指針131

指向對象的指針可以通過對象指針訪問對象和對象的成員,如:

*pt//pt所指向對象t1

(*pt).hour//pt所指向對象中的hour成員,即t1.hourpt->hour//pt所指向對象中的hour成員,即t1.hour

(*pt).get_time()//調用pt所指向的對象中的get_time函數,即t1.get_time

pt->get_time()//調用pt所指向的對象中的

get_time函數,即t1.get_time對象指針132

指向對象成員的指針指向對象數據成員的指針:數據類型名*指針變數名;

p1=&t1.hour;

//將對象t1的數據成員hour的地址賦給p1,p1指向t1.hourcout<<*p1<<endl;

//輸出t1.hour的值對象指針133

指向對象成員的指針指向對象成員函數的指針:1、普通函數:數據類型名(*指針變數名)(參數表列);

2、指向公用成員函數的指針變數:數據類型名(類::*指針變數名)(參數表列);3、使指針變數指向一個公用成員函數的一般形式為:

指針變數名=&類名::成員函數名;例2.8.1。對象指針每個對象中的數據成員都分別佔有存儲空間,如果對同一個類定義了n個對象,則有n組同樣大小的空間以存放n個對象中的數據成員。但是,不同對象都調用同一個函數代碼段。當不同對象的成員函數引用數據成員時,怎麼能保證引用的是所指定的對象的數據成員呢?假如,對於定義的Box類,定義了3個同類對象a,b,c。如果有a.volume(),應該是引用對象a中的height,width和length,計算出長方體a的體積。如果有b.volume(),應該是引用對象b中的height,width和length,計算出長方體b的體積。而現在都用同一個函數段,系統怎樣使它分別引用a或b中的數據成員呢?this指針在每一個成員函數中都包含一個特殊的指針,這個指針的名字是固定的,稱為this。它是指向本類對象的指針,它的值是當前被調用的成員函數所在的對象的起始地址。例如,當調用成員

温馨提示

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

评论

0/150

提交评论