對象數組
如果構造函數只有一個參數,在定義數組時可以直接在等號後面的花括號內提供。Student stud[3]={90,92,01};//合法
如果構造函數有多個參數,則不能用在定義時直接所提供所有實參的方法。
但可以如下定義:
//構造函數有三個參數:學號,年齡,成績 Student stud[3]{ Student(1000,19,22); Student(1001,19,22); Student(1002,19,22); };
對象指針
指向對象的指針
class Box {public: Box(int h=10,int w=10,int len=10);
int s; int volume(); private: int height; int width; int length; }; Box::Box() { height=h; width=w; length=len; } int Box::volume(){ return(height*width*length); }
Box *ptr;//指向對象的指針
Box t1;
ptr=&t1;
指向對象成員的指針
1)指向對象數據成員的指針
定義的一般形式為:
數據類型名 *指針變量名;
int *p1; p1=&t1.s;// s是public類型數據
2)指向對象成員函數的指針
定義指向對象成員函數的指針變量和定義指向普通函數的指針變量方法有所不同。對比如下:
類型名(*指針變量名)(參數列表); void (*p)( ); p=fun; (*p) ( );//定義fun函數 ////////////////////////////////////////// 針對指向對象成員函數的指針要求: 指針變量的類型必須與賦值號右側函數的類型匹配,滿足一下3個方面 1)函數參數的類型和參數個數 2)函數返回值的類型 3)所屬的類 采用如下格式: void(Time::*p2)(); 一般形式為: 數據類型名(類名::*指針變量名)(參數列表); p2=&Time::get_time; 使指針變量指向一個公用成員函數的一般形式為 指針變量名=&類名::成員函數名
#include<iostream> using namespace std; class Time {public: Time(int,int,int); int hour; int minute; int sec; void get_time(); }; Time::Time(int h,int m,int s) { hour=h; minute=m; sec=s; } void Time::get_time(){ cout<<hour<<":"<<minute<<":"<<sec<<endl; } int main() { Time t1(10,2,39); int *p1=&t1.hour; cout<<*p1<<endl; t1.get_time(); Time *p2=&t1; p2->get_time(); void(Time::*p3)();//定義指向Time類公用成員函數的指針變量p3 p3=&Time::get_time;//使p3指向Time類公用成員函數get_time (t1.*p3)();//調用p3指向的成員函數(t1.get_time);不應寫成p3=&ti.get_time(成員函數不是存放在對象的空間中的,而是存放在對象外的空間中的。) } // main函數第8.9兩行可以寫成一行void(Time::*p3)()=&Time::get_time
this指針
在每一個成員函數中都包含一個特殊的指針,這個指針的名字是固定的,稱為this指針。
它是指向本類對象的指針,它的值是當前被調用的成員函數所在的對象的起始地址。
//當調用a.volume時候,實際 上執行 (a.height)*(a.width)*(a.length)
公用數據的保護
既要使數據能在一定范圍內共享,又保證它不被任意修改,這是可以把有關的數據定義為常量。
常對象
可以在定義對象的時候加關鍵字const,指定對象為常對象。常對象必須要有初值,如
Time const t1(23,67,7);
這樣對象t1中的所有數據成員的值都不能被修改。
類名 const 對象名(實參表)或者 const 類名 對象名(實參表)
Tips:
1)如果一個對象被聲明為常對象,則通過該對象只能調用它的常成員函數,而不能調用該對象的普通成員函數(除了析構函數和構造函數)。常成員函數時常對象唯一的對外接口。
引用常對象中的數據成員,只須將該成員函數聲明為const即可。 void get_time() const;
2)常成員函數可以訪問常對象中的數據成員,但仍然不能修改其值。若對數據成員聲明為mutable,可以被修改。
以上兩點保證常對象中數據成員的值絕對不會改變。
常對象成員(數據成員和函數成員)
常數據成員
其作用和用法與一般常變量相似,用關鍵字const來聲明常數據成員。其值不可修改;
只能通過構造函數的參數初始化表對常數據成員進行初始化,任何其他函數都不能對常數據成員賦值。
常成員函數
如果將成員函數聲明為常成員函數,則只能引用本類中的數據成員,而不能修改它們。
聲明常成員函數的一般形式:
類型名 函數名 (參數表)const
const是函數類型的一部分,在聲明函數和定義函數時都要有const關鍵字,在調用時不必加const。常成員函數可以引用const數據成員,也可以引用非const的數據成員。
不用誤以為常對象中的成員函數都是常成員函數,常對象只保證其數據成員是常數據成員,其值不被修改。如果在常對象中的成員函數未加const聲明,系統把它編譯為非const成員函數。
常成員函數不能調用另一個非const成員函數。
指向對象的常指針
將指針變量聲明為const類型,這樣指針變量始終保持為初值,不能改變,即其指向不變。
Time t1(2,2,3),t2; Time *const ptr1; ptr1=&t1; ptr1=&t2;//錯誤,不能改變ptr1的指向
類名 *const 指針變量名
指向常對象的指針變量
常變量指針
const char *ptr;
定義指向常變量的指針變量的一般形式為:
const 類型名 *指針變量名;
1)如果一個變量已被聲明為常變量,只能用指向常變量的指針指向它。
不能用一般的(指向非const型變量的)指針去指向它;如
const char c[ ]="boy"; const char *p1; p1=c; char *p2=c;//不合法,p2不是指向常變量的指針變量
2)指向常變量的指針變量除了可以指向常變量外,還可以指向未被聲明為const的變量。此時不能通過此指針變量改變該變量的值。如
char c1='a'; const char *p; p=&c1; *p='b';//非法,不能通過p改變變量c1的值 c1='b';
3)如果函數的形參是指向非const型變量的指針,實參只能用指向非const變量的指針,而不能用指向const變量的指針。這樣,在執行函數的過程中可以改變形參指針變量所指向的變量的值。如果函數的形參是指向const型變量的指針,在執行函數的過程中顯然不能改變指針變量所指向的變量的值,因此允許實參是指向const變量的指針,或指向非const變量的指針。如
const char str[]="boy"; void fun(char *ptr); fun(str);//調用fun函數,實參是const變量的地址,非法
用指針變量作形參時形參和實參的對應關系
對象的常引用
類似於變量的引用
const型數據的總結
對象的動態建立與釋放
前面介紹的方法定義的對象都是靜態的,在程序運行過程中,對象所占的空間是不能隨時釋放的。
動態建立對象:要用到對象的時候建立對象,不用的時候就撤銷它,釋放它所占的內存空間。
如new Box;
編譯系統開辟了一段內存空間,並在此空間中存放一個Box類對象,同時調用該類的構造函數,以使該對象初始化。但是此時用戶無法訪問這個對象,因為這個對象既沒有對象名,用戶不知道它的地址。這種對象成為無名對象,存在但沒有名字。
用new運算符動態地分配內存後,將返回一個指向新對象的指針的值,即所分配的內存空間的起始地址。用戶可以獲得這個地址,並通過這個地址來訪問這個對象。需要定義一個指向本類的對象的指針變量來存放該地址。
Box *pt; pt=new Box;
C++還允許在指向new時,對新建立的對象進行初始化。
Box *pt = new Box(12,13,18);
這種寫法把上面兩個語句合並為一個語句,並指定初值。
在不需要使用由new建立的對象時,可以用delete運算符予以釋放。
delete pt;
在執行delete運算符時,在釋放內存空間之前,自動調用析構函數,完成有關善後清理工作。
對象的賦值和賦值
對象的賦值
對象名1 = 對象名2
Student stud1,stud2; .... .... stud2=stud1;
1)對象的賦值只對其中的數據成員賦值,而不對成員函數賦值。不同對象的成員函數 是同一個函數代碼段,不需要,也無法對它們賦值。
2)類的數據成員中不能包括動態分配的數據,否則在賦值時可能出現嚴重後果。
對象的復制
有時需要用到多個完全相同的對象,即對象的復制。類名 對象2(對象1)。如:
Box box2(box1);//用已有的對象box1去克隆一個新對象box2
C++還提供另一種方便用戶的復制形式,用復制號代替括號。
Box box2=box1;
類名 對象名1=對象名2;
區別對象的復制與賦值:
對象的賦值是對一個已經存在的對象賦值,因此必須先定義被賦值的對象。而對象的復制是從無到有地建立一個新對象,並使它與一個已有的對象完全相同。
靜態數據成員:如果想在同類的多個對象之間實現數據共享,也不用使用全局對象,可以用靜態的數據成員。
class Box{ public: int volume(); private: static int height;// 靜態的數據成員 int width; int length; };
如果希望各對象中的數據成員的值是一樣的,就可以把它定義為靜態數據成員;
靜態數據成員只占用一份空間(而不是每個對象分別為它保留一份空間)。
說明:
1)如果只聲明了類而未定義對象,則類的一般數據成員是不占內存空間的,只有在定義對象時,才為對象的數據成員分配空間。但是靜態數據成員不屬於某一個對象,在為對象所分配的空間中不包括靜態數據成員所占用的空間。靜態數據成員是在所有對象之外單獨開辟空間。只要類中指定了靜態數據成員,即使不定義對象,也為靜態數據成員分配空間,它可以被引用。
2)靜態數據成員是在程序開始運行時被分配空間,到程序結束時才釋放空間。
3)靜態數據成員可以初始化,但只能在類外進行初始化。
int Box::height = 10;
一般形式為:
數據類型 類名::靜態數據成員名=初值;
在初始化時不必加static。不能用參數初始化表對靜態數據成員初始化。默認值為0。下面是錯誤的:
Box(int h,int w,int len):height(h){}//錯誤
4)靜態數據成員既可以通過對象名引用,也可以通過類名來引用。
#include<iostream> using namespace std; class Box {public: // Box(); Box(int,int); int volume(); //private: static int height; int width; int length; }; Box::Box(int w,int len) { width=w; length=len; } int Box::volume(){ return(height*width*length); } int Box::height=10;//對靜態數據成員初始化 int mian() { Box box1(18,29),box2(18,2); //cout<<"the box1 is:"<<box1.volume()<<endl; cout<<box1.height<<endl;//通過對象名引用靜態數據成員 cout<<box2.height<<endl; // Box box2(14,12,48); //cout<<"the box2 is:"<<box2.volume()<<endl; cout<<Box::height<<endl;//通過類名引用靜態數據成員 cout<<box1.volume()<<endl; // return 0; }
可以看到,如果靜態數據成員是public型,在類外可以通過對象名引用公用的靜態數據成員,也可以通過類名引用靜態數據成員。即使沒有定義對象,也可以通過類名引用靜態數據成員,說明靜態數據成員屬於類,不屬於對象。若是private,則不可在類外直接引用,必須通過公用的成員函數引用。
5)有了靜態數據成員,各對象之間的數據有了溝通的渠道,實現數據共享。因此可以不使用全局變量。注意公用靜態數據成員與全局變量不同,靜態數據成員的作用域只限於定義該類的作用域內。
靜態成員函數
成員函數也可以是靜態的,在類中聲明函數的前面加static即可。
static int volume();
靜態成員函數時類的一部分而不是對象的一部分。如果要在類外調用公用的靜態成員函數,要用類名和域運算符“::”。
Box::volume();
實際上也越小通過對象名調用靜態成員函數。如 a.volume( );但這不意味著此函數屬於對象a,而只是用a的類型而已。
靜態成員函數是為了處理靜態數據成員。