?? c++10.dat
字號:
第十章 類與對象
第一節(jié) 類與對象的概述
我們的周圍是一個真實的世界,不論在何處,我們所見到的東西都可以看成是對象.人、動物、工廠、汽車、植物、建筑物、割草機、計算機等等都是對象,現(xiàn)實世界是由對象組成的.
對象多種多樣,各種對象的屬性也不相同.有的對象有固定的形狀,有的對象沒有固定的形狀,有的對象有生命,有的對象沒有生命,有的對象可見,有的對象不可見,有的對象會飛,有的對象會跑,有的對象很高級,而有的對象很原始,….各個對象也有自己的行為,例如:球的滾動、彈跳和縮小,嬰兒的啼哭、睡眠、走路和眨眼,汽車的加速、剎車和轉(zhuǎn)彎,等等.但是,各個對象可能也有一些共同之處,至少它們都是現(xiàn)實世界的組成部分.
人們是通用過研究對象的屬性和觀察它們的行為而認識對象的.我們可以把對象分成很多類,每一大類中又可分成若干小類,也就是說,類是分層的.同一類的對象具有許多相同的屬性和行為,不同類的對象可具有許多相同的屬性和類似的行為,例如:嬰兒和成人,人和猩猩,小汽車和卡車、四輪馬車、冰鞋等等都有共同之處,類是對對象的抽象.
在C++中,就是用類來描述對象的,類是對現(xiàn)實世界的抽象得到的.例如,在真實世界中,同是人類的張三和李四,有許多共同點,但肯定也有許多不同點.當用C++描述時,相同類的對象具有相同的屬性和行為,它把對象分為兩個部分:數(shù)據(jù)(相當于屬性)和對數(shù)據(jù)的操作(相當于行為).我們刻畫張三和李四的數(shù)據(jù)可能用姓名、性別、年齡、職業(yè)、住址等,而對數(shù)據(jù)的操作可能是讀或設(shè)置它們他們的名字、年齡等.
從程序設(shè)計的觀點來說,類就是數(shù)據(jù)類型,是用戶定義的數(shù)據(jù)類型.這種類型的使用雖然與C++內(nèi)置的數(shù)據(jù)類型類似,但是也有很大的區(qū)別.例如,C++內(nèi)置的浮點類型并不針對任何具體問題,僅僅與機器的存儲單元相對應,而類是用戶根據(jù)具體問題的需要而定義的,也就是說,類與具體問題相適應.我們可以通過定義所需要的類,來擴展程序設(shè)計語言解決問題的能力.
當我們把現(xiàn)實世界分解為一個個的對象,解決現(xiàn)實世界問題的計算機程序也與此相對應,由一個個對象組成,這些程序就稱為面向?qū)ο蟮某绦?編寫面向?qū)ο蟪绦虻倪^程就稱為面向?qū)ο蟮某绦蛟O(shè)計(Object-Oriented Programming,簡稱為OOP).OOP技術(shù)能夠?qū)⒃S多現(xiàn)實的問題歸納成為一個簡單解,支持OOP的語言也很多,C++是應用最廣泛的、支持OOP的語言,第一個成功的支持OOP的語言是Smalltalk.
面向?qū)ο蟮某绦蛟O(shè)計(OOP)使用軟件的方法模擬真實世界的對象,它利用了類的關(guān)系,即同一對象(如同一類運載工具)具有相同的特點;還利用了繼承甚至多重繼承的關(guān)系,即新建的對象類是通過繼承現(xiàn)有類的特點而派生出來的,但是又包含了其自身特有的特點,如子女有父母的許多特點,但是矮個子父母的子女也可能是高個子.
面向?qū)ο蟮某绦蛟O(shè)計(OOP)使程序設(shè)計過程更自然和直觀.也就是說,面向?qū)ο蟮某绦蛟O(shè)計模擬了真實世界的對象(它們的屬性和行為).OOP還模擬了對象之間的通信,就像人們之間互送消息一樣(如軍官命令部隊立正),對象也是通過消息進行通信的.
C++語言是當今應用最廣泛的程序設(shè)計語言,它與C語言兼容,既支持面向?qū)ο蟮某绦蛟O(shè)計,也支持面向?qū)ο蟮某绦蛟O(shè)計方法.在前面的章節(jié)中,我們編寫的程序是由一個個函數(shù)組成的,可以說是結(jié)構(gòu)化的程序.從本章開始,我們編寫的程序是由對象組成的,也就是說,將要學習用C++語言進行面向?qū)ο蟮某绦蛟O(shè)計.
什么叫類,什么叫對象?我們已經(jīng)知道什么叫變量.假定我們在main函數(shù)中定義了一個整型變量nInteger:
void main()
{
int nInteger;
…
}
則在main函數(shù)中為nInteger分配棧內(nèi)存,保存變量nInteger的值,并在main返回時,釋放該內(nèi)存.在面向?qū)ο蟮某绦蛟O(shè)計中,nInteger也稱之為對象.所謂對象就是一個內(nèi)存區(qū),它存儲某種類型的數(shù)值,變量就是有名的對象.對象除可以用上述定義的方法來創(chuàng)建外,也可以用new表達式創(chuàng)建,也可能是應用程序運行時臨時創(chuàng)建的,例如,在函數(shù)調(diào)用和返回時,均會創(chuàng)建臨時對象.
對象是有類型的,例如,我們上面定義的nInteger對象就是整型的.一個類型可以定義許多對象,一個對象有一個確定的類型,可以這么說:int型變量是int類型的實例.以后,我們也常說:對象是類的實例,那么int是不是一個類呢?
實際上,我們所說的類,并非指C++中的那些基本的數(shù)據(jù)類型.C++中引入了class關(guān)鍵字來定義類,它也是一種數(shù)據(jù)類型.類是C++支持面向?qū)ο蟮某绦蛟O(shè)計的基礎(chǔ),它支持數(shù)據(jù)的封裝、隱藏等.類與我們前面學習過的結(jié)構(gòu)類似,實際上C++中也可以用struct關(guān)鍵字來定義類(雖然很少使用).
我們前面學習的結(jié)構(gòu)中,只有數(shù)據(jù)成員.實際上,類中除可以定義數(shù)據(jù)成員外,還可以定義對這些數(shù)據(jù)成員(或?qū)ο?操作的函數(shù),也正是這些函數(shù)限制了對對象的操作,即不能對對象進行這些操作函數(shù)之外的其它操作,類的成員也有不同的訪問權(quán)限.下面,我們將要介紹怎樣定義類及類的成員.
1.1 類的定義
類定義的一般形式如下:
class Name
{
細節(jié)
};
類的定義由頭和體兩個部分組成.類頭由關(guān)鍵字class開頭,然后是類名,其命名規(guī)則與一般標識符的命名規(guī)則一致,有時可能有附加的命名規(guī)則,例如美國微軟公司的MFC類庫中的所有類均是以大寫字母'C'開頭的.類體包括所有的細節(jié),并放在一對花括號中.類的定義也是一個語句,所以要有分號結(jié)尾,否則,會產(chǎn)生難以理解的編譯錯誤.
類體定義類的成員,它支持兩種類型的成員:
1. 數(shù)據(jù)成員,它們指定了該類對象的內(nèi)部表示.
2. 成員函數(shù),它們指定該類的操作.
類成員有三種不同的訪問權(quán)限:
1. 公有(public)成員可以在類外訪問.
2. 私有(private)成員只能被該類的成員函數(shù)訪問.
3. 保護(protected)成員只能被該類的成員函數(shù)或派生類(有關(guān)基類和派生類的概念我們在下一章介紹)的成員函數(shù)訪問.
數(shù)據(jù)成員通常是私有的,成員函數(shù)通常有一部分是公有的,一部分是私有的.公有的成員函數(shù)可在類外被訪問,也稱之為類的接口.我們可以為各個數(shù)據(jù)成員和成員函數(shù)指定合適的訪問權(quán)限,類定義常有下面的形式:
class Name {
public:
類的公有接口
private:
私有的成員函數(shù)
私有的數(shù)據(jù)成員定義
};
私有的成員與公有的成員的先后次序無關(guān)緊要.不過公有的接口函數(shù)放在前面更好,因為,有時我們可能只想知道怎樣使用一個類的對象,那只要知道類的公有接口就行了,不必閱讀private關(guān)鍵字以下的部分.
1.2 類成員函數(shù)的定義
類的成員函數(shù)通常在類外定義,一般形式如下:
返回類型 類名::函數(shù)名(形參表)
{
函數(shù)體
}
雙冒號::是域運算符,它主要用于類的成員函數(shù)的定義.
1.3 使用對象
定義了類以后,就可以定義類類型的變量(或?qū)ο?,例如:
void DrawLine(Point& p1, Point& p2)
{
Point MidPoint;
…
}
函數(shù)DrawLine中定義了一個Point對象MidPoint.
象結(jié)構(gòu)一樣,類類型的變量也能夠作為函數(shù)參數(shù),以值或引用的方式傳遞,也可以作為函數(shù)的返回值,以及在賦值語句中被復制.
我們已經(jīng)知道:結(jié)構(gòu)變量通過"."運算符訪問其數(shù)據(jù)成員,對象數(shù)據(jù)要通過其成員函數(shù)進行修改或讀出.
Point thePoint;
…
thePoint.SetPt(5, 10);
…
if(thePoint.GetX() < 0) …
可以看到,調(diào)用成員函數(shù)語法與結(jié)構(gòu)變量訪問其數(shù)據(jù)成員的語法相同:
對象名. 成員函數(shù)名 (實參表)
成員函數(shù)也可以通過指向?qū)ο蟮闹羔?調(diào)用形式為:
指向?qū)ο蟮闹羔?>成員函數(shù)名 (實參表)
注意:
(1) 對私有數(shù)據(jù)成員的訪問只能通過成員函數(shù),下面的語句是非法的:
thePoint.xVal = 5; // 非法
(2) 不要混淆了類與對象的概念.類是用戶定義的數(shù)據(jù)類型(不占內(nèi)存),對象是類的實例(占內(nèi)存單元),例如:
Point pt1, pt2, pt3;
定義了三個Point對象pt1、pt2和pt3.
例如:
動態(tài)對象創(chuàng)建
有時我們知道程序中需要創(chuàng)建多少對象,但是多數(shù)情況下,我們不能預知所需對象的確切數(shù)量.比如公路交通管理系統(tǒng)必須同時處理多少輛汽車?一個三維建筑設(shè)計系統(tǒng)需要處理多少個模型?解決這些編程問題的方法,是要能夠支持在運行時動態(tài)創(chuàng)建和銷毀對象.
一個對象被動態(tài)創(chuàng)建時,依次發(fā)生兩件事情:
1. 為對象分配內(nèi)存;
2. 調(diào)用構(gòu)造函數(shù)來初始化這塊內(nèi)存.
同樣,一個對象被動態(tài)銷毀時,按照順序發(fā)生了下面兩件事情:
1. 調(diào)用析構(gòu)函數(shù)清除對象;
2. 釋放對象的內(nèi)存;
C++提供了兩個運算符new和delete,分別用來完成動態(tài)對象的創(chuàng)建和銷毀.當我們用new創(chuàng)建一個對象時,就在堆里為對象分配內(nèi)存并調(diào)用相應的構(gòu)造函數(shù).new返回一個指向剛剛創(chuàng)建的對象的指針;當我們用delete銷毀一個對象時,就調(diào)用相應的析構(gòu)函數(shù),釋放掉分配的堆內(nèi)存,delete運算符的操作數(shù)是指向?qū)ο蟮闹羔?需要注意的是:用new創(chuàng)建的對象必須用delete銷毀,否則,會出現(xiàn)內(nèi)存泄漏.
舉個例子說明利用new和delete動態(tài)創(chuàng)建和銷毀對象的過程:
#include <iostream.h>
class Tree
{
public:
Tree(int height)
{
cout<<"tree object is creating"<<endl;
this->height = height;
}
~Tree()
{
cout<<"tree object is deleting"<<endl;
}
void display()
{
cout<<"this tree is "<<height<<" meters high"<<endl;
}
private:
int height;
};
void main()
{
Tree* tree = new Tree (100);
tree->display();
delete tree;
}
程序的輸出結(jié)果如下:
tree object is creating
this tree is 100 meters high
tree object is deleting
main( )函數(shù)中的第一個語句,是用new運算符動態(tài)創(chuàng)建一個Tree類對象,new后面括號中的100,實際上是new創(chuàng)建對象時,傳給構(gòu)造函數(shù)的參數(shù).main( )函數(shù)的第二個語句是調(diào)用對象的顯示函數(shù),打印出的結(jié)果顯示樹高為100米,可見new操作符確實調(diào)用了類的構(gòu)造函數(shù)display.main( )函數(shù)的最后一個語句用delete運算符銷毀用new創(chuàng)建的對象.對象一旦被銷毀后,就不再存在.如果繼續(xù)訪問對象tree的數(shù)據(jù)成員或成員函數(shù),則程序會產(chǎn)生錯誤.
1.4 this指針
C++中,定義了一個this指針,用它指向調(diào)用非靜態(tài)成員函數(shù)的對象.也就是說,this指針僅能在類的成員函數(shù)中訪問,它指向調(diào)用該函數(shù)的對象,在后面我們要介紹的靜態(tài)成員函數(shù)沒有this指針.
當一個非靜態(tài)的成員函數(shù)被一個對象調(diào)用時,對象的地址作為一個隱含的參數(shù)傳給被調(diào)用的函數(shù).例如:
myDate.setMonth( 3 );
可被解釋為:
setMonth( &myDate, 3 );
下面的成員函數(shù)setMonth,可用兩種方法實現(xiàn):
void Date::setMonth( int mn )//使用隱含的this指針
{
month = mn;
}
void Date::setMonth( int mn )//顯式使用this指針
{
this->month = mn;
}
雖然顯式使用this指針的情況并不是很多,但是,this指針有時是有用的.例如,下面的賦值是不允許的:
void Date::setMonth( int month)
{
month = month;
}
但可以用this指針來解決:
void Date::setMonth( int month)
{
this->month = month;
}
類的每個成員函數(shù)都訪問特殊的指針-this.This指針保留了激活成員函數(shù)的對象地址(也就是說,this總是指向目標對象).This指針僅僅在成員函數(shù)內(nèi)部是合法的,而且名稱this是C++的保留字.
每個成員函數(shù)所收到的第一個參數(shù)就是this指針.程序員沒有必要明確定義這個this指針,但是,它總是存在的.This指針通常是每個成員函數(shù)(非靜態(tài))隱含的第一個參數(shù).編譯器在每個成員函數(shù)的聲明中插入這個隱含參數(shù).當成員函數(shù)使用類的成員的絕對名稱的任何時候,它隱式使用this指針.編譯器在引用成員函數(shù)內(nèi)部的每個表達式中插入this指針(如果用戶并沒有這樣做的話).
第二節(jié) 構(gòu)造函數(shù)與析構(gòu)函數(shù)
在C++中,有兩種特殊的成員函數(shù),即是構(gòu)造函數(shù)和析構(gòu)函數(shù),下面分別予以介紹.
2.1 構(gòu)造函數(shù)
變量應該被初始化,我們已經(jīng)知道了簡單變量的初始化、數(shù)組的初始化、結(jié)構(gòu)和結(jié)構(gòu)數(shù)組的初始化.對象也需要初始化,應該怎樣初始化一個對象呢?
C++中定義了一種特殊的初始化函數(shù),稱之為構(gòu)造函數(shù).當對象被創(chuàng)建時,構(gòu)造函數(shù)自動被調(diào)用.構(gòu)造函數(shù)有一些獨特的地方:函數(shù)的名字與類名相同,它也沒有返回類型和返回值.
例如:
class Point {
public:
Point(int x = 0, int y = 0);
…
};
類Point的構(gòu)造函數(shù)有兩個參數(shù),它們是賦給xVal、yVal的初始值,該構(gòu)造函數(shù)的原型也為實參指定了缺省值0.
Point::Point(double x, double y)
{
xVal = x;
yVal = y;
}
我們也可以把該構(gòu)造函數(shù)定義為內(nèi)聯(lián)函數(shù)的形式:
class Point {
Point (int x=0, int y=0) {xVal = x; yVal = y;} // 構(gòu)造函數(shù)
…
};
如果不采用Point構(gòu)造函數(shù),我們將不得不調(diào)用SetPt函數(shù)初始化.可見,使用Point構(gòu)造函數(shù)方便了編程,簡化了程序代碼.
現(xiàn)在,我們可以定義Point類對象并立即初始化它們:
Point pt1(10, 20); // xVal和yVal的初值分別為10和20
Point pt2; // xVal和yVal的初值均為0
構(gòu)造函數(shù)也可以重載:
class Point {
int xVal, yVal;
public:
Point (int x, int y) { xVal = x; yVal = y; }
Point (float, float); //極坐標
Point (void) { xVal = yVal = 0; }
…
};
Point::Point (float len, float angle) //極坐標
{
xVal = (int) (len * cos(angle));
yVal = (int) (len * sin(angle));
}
創(chuàng)建Point對象時,可以使用這三種構(gòu)造函數(shù)中的任一個.
Point pt1(10, 20); // 笛卡兒坐標
Point pt2(60.3, 3.14); // 極坐標
Point pt3; // 原點
2.2 成員初始化表
一、常量成員
二、引用成員
三、類對象成員
類中數(shù)據(jù)成員可以通過構(gòu)造函數(shù)來初始化,例如:
程序1
class Image {
public:
Image(const int w, const int h);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -