類與對象
【學習目標】
本章主要介紹類類型的定義、構造函數與析構函數的定義與作用、友元函數與友元類的聲明與作用、派生類的定義與作用、虛函數和多態性的概念、靜態數據成員的聲明與定義、模板類的定義與實例化等內容。通過本章的學習,要求同學們:
掌握類的概念,類類型的定義格式,類與結構的關系,類與操作符重載,類的成員屬性,類的封裝性,類的繼承性,構造函數和析構函數的作用,this指針的含義,類對象的定義,友元函數與友元類的作用;了解inline成員函數,靜態數據成員,類的多態性與虛函數,類模板等內容。
類:是對具有共同屬性和行為的一類事物的抽象描述,共同屬性被描述為類中的數據成員,共同行為被描述為成員函數。 類所描述的事物具有共同的屬性和行為(操作),但每一個具體事物(又稱為個體,實例或對象)都具有屬于自己的屬性值和行為特征。
人的共同屬性有姓名,性別,出生日期等等。人的共同行為有愛好,工作,學習等等。
同結構與聯合一樣,類是一種自定義類型,它包括定義數據成員和定義函數成員(又稱成員函數),用數據成員來描述同類事物的屬性,用成員函數來描述它們的行為。
類定義變量以及訪問數據成員與函數成員與結構類型相同。
一、類的定義
1.類的定義格式:
clsaa類名{成員表};
其中:
類名:為自定義的類的名稱,可用來定義變量,函數的數據類型。
成員表:為類包含的數據成員和函數成員。
每一個成員都具有一定的存取權限,或者稱存取屬性,訪問權限,訪問屬性。C++有三個指明符:
public:公用(公有,公共)訪問屬性,成員可以任意函數所訪問。
private:私有訪問屬性,成員只能為該類的成員函數所訪問。
protected:保護訪問屬性,成員只能為該類成員函數以及該類的派生類中的成員函數訪問。
類中的數據成員一般定義為私有,這樣只允許該類的成員函數訪問,不允許該類以外的任何函數訪問,從而使類對象中的數據得到隱藏和保護。
類與結構在定義時的區別:
結構類型定義時在第一個存取指明符前定義的成員具有默認的public訪問屬性,類在定義時為private訪問屬性。
2.定義格式舉例:
P245:
1.struct ca
{
int a;
int b;
}ax;
2. class cb
{ int a;
int b;
} bx;
3.class cc
{ int a;
public:
void init(int aa){a=aa;}
int getdata(){return a;}
}cx;
4.class cd
{ char *a;
int b;
public:
void init(char *aa,int bb)
{a=new char[strlen(aa)+1];
strcpy(a,aa);
b=bb;
}
char *geta(){trturn a;}
int getb(){return b;}
void output(){cout<<a<<’ ‘<<b<<endl;}
}dx;
5.class ce
{
private:
int a,b;
int getmax(){return(a>b?a:b);}
public:
int c;
void setvalue(int x1,int x2,int x3)
{a=x1; b=x2; c=x3;}
int getmax()
{int d=getmax():
return (d>c?d:c);
}
}ex,*ep=&ex;
3.類的定義與使用說明
①類中的函數成員與數據成員都是在給定類中定義的。在訪問數據成員與函數成員時必須通過對象(變量)調用。
②類的成員函數能夠直接訪問所在類中定義的所有數據成員與函數成員。
③一個類的每個成員函數中都默認有一個所屬類的指針參數(this指針),對數據成員或函數成員的訪問,就是對this指針所指對象的訪問。
④成員函數可以在類中給出定義,也可以使成員函數的原型與定義分開。
如:P249
⑤成員函數可以通過inline定義的內聯函數。
如:P250
⑥成員函數可以說明為可選參數函數。
如:P250
⑦每個類類型的大小,即對應對象所占存儲空間的字節數等于所有數據成員所占存儲字節數的總和。
⑧類中的成員函數允許重載,包括操作符的重載。
例:P251 例8.1
二、構造函數
構造函數和析構函數屬于類中的成員函數。
構造函數與所在的類具有相同的名字,并且不帶任何返回類型,也不要返回任何值。
建立構造函數的作用是為對象中的數據成員賦值值。一個類的構造函數將在定義該類對象的時自動調用,完成給對象賦初值的任務,而不允許像其它成員函數那樣要由用戶直接調用。一般把每個構造函數定義為類的公用成員。
1.無參構造函數和有參構造函數
例如:
例:P255 例8.2
當用類類型定義一個類對象時,若需要它自動調用無參構造函數對其進行初始化,則只需給出對象名,若需要它自動調用有參構造函數對其進行初始化,則給出的對象名后必須帶有圓括號括起來的實參數表。
類對象定義所帶的參數表中若只有一個參數時,也可以用賦值號代替圓括號。
如:x(5) ---> x=5;
當由動態分配一個類對象時,對該對象進行初始化所需要的參數表應放在new 操作符后的類名的后面,當然調用無參數構造函數時就不帶參數表。
如:
array *s1=new array;
array *s2=new array(a,6);
例:P258 例8.3
2.拷貝構造函數
若構造函數的參數是針對同類對象的引用時,則稱之為拷貝構造函數或復制構造函數。
通過調用拷貝構造函數,可以定義全個與已有對象完全相同的對象。這個已有的對象是通過 引用參數傳遞給構造函數的,可稱為參數對象。
若一個類中沒有定義拷貝構造函數,則系統為該類定義一個默認的拷貝構造函數。
系統默認的拷貝構造函數把參數對象的值賦給初始化的對象中,使得被初始化對象的每個成員值與初始化對象的每個成員值完全相同。
有的類的數據成員中存在著指針,且該指針指向動態分配的存儲空間。
例:P260
3.賦值操作符的重載
4.構造函數中的初始化表
在構造函數中對數據成員進行初始化時,可采用兩種方法:
①在函數體中使用賦值語句把表達式的值直接賦給成員變量。
②用初始化表進行初始化。
如:P262
當帶有初始化表的構造函數執行時,首先執行初始化表,然后才執行函數體。在執行初始化時按照類中數據成員定義的先后次序給數據成員賦初值。
三、析構函數
析構函數的名字與類名相同,只是在函數名前加上(~)以示區別。
析構函數不允許帶任何參數,并且也不允許帶有返回類型。
通常析構函數是由系統執行程序時自動調用的,但調用時機正好相反,構造函數是在對象生成時調用,析構函數是在對象撤消時調用,且在調用執行后才真正撤消對象。
必須把析構函數定義為公用成員函數。
系統默認定義的析構函數為:
~x(){};
例:P263
四、友元函數和友元類
在一個類中,類對象的私有成員只能由該類的成員函數訪問,外部定義的普通函數和其它類中定義的成員函數都不得訪問,這些外部函數只能通過該類提供的公用成員函數進行訪問,這樣有利于數據的封裝,隱藏和保護,符合面向程序設計的要求。
為了提高訪問效率,C++允許在一個類中把外部的有關函數或類聲明(或稱為說明,宣布等)為它的友元函數或友元類。
被聲明為一個類的友元函數或友元類具有直接訪問該類的私有成員的特權。
例:P265例8.4 (友元函數)
P269例8.5 (友元類)
五、類的繼承
在C++中允許定義類之間的繼承關系,當一個類繼承另一個類時,這個類被稱為繼承類,派生類或子類,另一個類被稱為被繼承類,基類或父類。
子類能夠繼承父類的全部特征,包括所有的數據成員和函數成員,并且子類還能夠定義父類所沒有的,屬于自己的特征,即自己定義的數據成員和函數成員。
使用繼承,可以避免代碼的重寫和調試。
例:P272
1.派生類定義的格式:
class派生類名:基類表{成員表};
基類表決定了針對每個基類的繼承方式。即在每個基類名前面可以使用的繼承權限指明符分別用public,protected和private表示公用繼承,保護繼承和私有繼承。默認為私有繼承,即派生類私有繼承該基類。
繼承方式所影響的是被繼承的原成員的訪問權限,但無論采用何種繼承方式,基類中的私有成員在派生類中是不可訪問的。因此繼承方式能實際影響的只是原基類中的公用成員和保護成員的訪問權限。
類成員受保護程度可分為public,protected和private三個等級,public最低,private最高。
在一個派生類中,其成員由兩部分組成,一部分是從基類繼承得到的,另一個部分是自己定義的新成員。
每個派生類對象所占的存儲空間的大小等于其基類部分的所有數據成員占有的存儲空間的大小與新定義部分的所有數據成員占有的存儲空間大小的總和。
2.格式舉例:
P273
構造函數的執行順序是,先執行基類構造函數,接著執行類成員所屬類的構造函數,最后執行自己定義的構造函數,而析構函數的執行順序正好相反,它先執行自己的函數體,接著執行類成員所屬類的析構函數,最后執行基類的析構函數。
P283 應用舉例:
例P283例8.6 ,8. 7