对象的赋值和复制(转)
一、對象的賦值和復制
1、對象的賦值
如果對一個類定義了兩個或多個對象,則這些同類的對象之間可以互相賦值,或者說,一個對象的值可以賦給另一個同類的對象。這里所指的對象的值是指對象中所有數(shù)據(jù)成員的值。
對象之間的賦值也是通過賦值運算符"="進行的。本來,賦值運算符"="只能用來對單個的變量賦值,現(xiàn)在被擴展為兩個同類對象之間的賦值,這是通過對賦值運算符的重載實現(xiàn)的(關(guān)于運算符的重載將在第4章中介紹)。實際上這個過程是通過成員復制(memberwise copy)來完成的,即將一個對象的成員值一一復制給另一對象的對應成員。
對象賦值的一般形式為:對象名1=對象名2;
注意:對象名l和對象名2必須屬于同一個類。
例如
Student studl,stud2;//定義兩個同類的對象
stud2=studl;//將studl各數(shù)據(jù)成員的值賦給stud2
通過下面的例子可以了解怎樣進行對象的賦值。
例9 對象的賦值。
#include <iostream>
using namespace std;
class Box
{public:
Box(int=10,int=10,int=10); //聲明有默認參數(shù)的構(gòu)造函數(shù)
int volume();
private:
int height;
int width;
int length; };
Box::Box(int h,int w,int len)
{height=h;
width=w;
length=len; }
int Box::volume()
{return(height*width*length); }//返回體積的值
int main()
{Box box1(15,30,25),box2; //定義兩個對象box1和box2
cout<<"The volume of box1 is "<<box1.volume()<<endl; //輸山boxl的體積
box2=box1; //將box的值財給1box2
cout<<"The volume of box2 is "<<box2.volume()<<endl; //輸出box2的體積
return 0; }
運行結(jié)果如下:
The volume Of boxl is 11250
The volume Of box2 is 11250
說明:
(1)對象的賦值只對其中的數(shù)據(jù)成員賦值,不對成員函數(shù)賦值。數(shù)據(jù)成員是占存儲空間的,不同對象的數(shù)據(jù)成員占有不同的存儲空間,賦值的過程是將一個對象的數(shù)據(jù)成員在存儲空間的狀態(tài)復制給另一對象的數(shù)據(jù)成員的存儲空間。而不同對象的成員函數(shù)是同一個函數(shù)代碼段,不需要、也無法對它們賦值。
(2)類的數(shù)據(jù)成員中不能包括動態(tài)分配的數(shù)據(jù),否則在賦值時可能出現(xiàn)嚴重后果(在此不作詳細分析,只需記住這一結(jié)論即可)。
2、對象的復制
有時需要用到多個完全相同的對象:
其一般形式為:類名對象2(對象1); //用對象l復制出對象2。
有這就是對象的復制機制。用一個已有的對象快速地復制出多個完全相同的對象。
如:Box box2(boxl);// 其作用是用已有的對象boxl去克隆出一個新對象box2。
可以看到:它與前面介紹過的定義對象方式類似,但是括號中給出的參數(shù)不是一般的變量,而是對象。在建立一個新對象時調(diào)用一個特殊的構(gòu)造函數(shù)——復制構(gòu)造函數(shù)(copy constructor)。這個函數(shù)的形式是這樣的:
//The copy constructor definition
Box::Box(const Box&b)
{height=b.height;
width=b.width;
length=b.length;}
說明:
1、復制構(gòu)造函數(shù)也是構(gòu)造函數(shù),但它只有一個參數(shù),這個參數(shù)是本類的對象(不能是其他類的對象),而且采用對象的引用的形式(一般約定加const聲明,使參數(shù)值不能改變,以免在調(diào)用此函數(shù)時因不慎而使對象值被修改)。此復制構(gòu)造函數(shù)的作用就是將實參對象的各數(shù)據(jù)成員值一一賦給新的對象中對應的數(shù)據(jù)成員。
2、復制對象的語句 Box box2(boxl);這實際上也是建立對象的語句,建立一個新對象box2。由于在括號內(nèi)給定的實參是對象,因此編譯系統(tǒng)就調(diào)用復制構(gòu)造函數(shù)(它的形參也是對象),而不會去調(diào)用其他構(gòu)造函數(shù)。實參boxl的地址傳遞給形參b(b是boxl的引用),因此執(zhí)行復制構(gòu)造函數(shù)的函數(shù)體時,將boxl對象中各數(shù)據(jù)成員的值賦給borg中各數(shù)據(jù)成員。
3、用戶可以在聲明類時定義復制構(gòu)造函數(shù),如果用戶自己未定義復制構(gòu)造函數(shù),則編譯系統(tǒng)會自動提供一個默認的復制構(gòu)造函數(shù),其作用只是簡單地復制類中每個數(shù)據(jù)成員。
4、還提供另一種方便用戶的復制形式,用賦值號代替括號.
其一般形式為:類名對象名1=對象名2;
如:Box box2=box1;//用boxl初始化box2
可以在一個語句中進行多個對象的復制,但是其作用都是調(diào)用復制構(gòu)造函數(shù)。
5、對象的復制和1節(jié)介紹的對象的賦值在概念上和語法上的不同。
請注意普通構(gòu)造函數(shù)和復制構(gòu)造函數(shù)的區(qū)別。
(1)在形式上
類名(形參表列); //普通構(gòu)造函數(shù)的聲明,如Box(int,int w,int leu);
類名(類名&對象名);//復制構(gòu)造函數(shù)的聲明,如Box(Box &b);
(2)在建立對象時,實參類型不同。系統(tǒng)會根據(jù)實參的類型決定調(diào)用普通構(gòu)造函數(shù)或復制構(gòu)造函數(shù)。如
Boxboxl(12,15,l6);//實參為整數(shù)(普通數(shù)據(jù)類型),調(diào)用普通構(gòu)造函數(shù)
Boxbox2(boxl); //實參是對象名(類數(shù)據(jù)類型),調(diào)用復制構(gòu)造函數(shù)
(3)在什么情況下被調(diào)用
普通構(gòu)造函數(shù)在程序中建立對象時被調(diào)用。
復制構(gòu)造函數(shù)在用已有對象復制一個新對象時被調(diào)用,在以下3種情況下需要克隆對象:
①程序中需要新建立一個對象,并用另一個同類的對象對它初始化。
②函數(shù)的參數(shù)為類的對象時,在調(diào)用函數(shù)時需要將實參對象完整地傳遞給形參,也就是需要建立一個實參的拷貝,這就是按實參復制一個形參,系統(tǒng)是通過調(diào)用復制構(gòu)造函數(shù)來實現(xiàn)的,這樣能保證形參具有和實參完全相同的值。
③函數(shù)的返回值是類的對象。在函數(shù)調(diào)用完畢需要將返回值(對象)帶回函數(shù)調(diào)用處時。此時需要將函數(shù)中的對象復制一個臨時對象并傳給該函數(shù)的調(diào)用處。
二、靜態(tài)成員
學習C語言時已了解全局變量,它能夠?qū)崿F(xiàn)數(shù)據(jù)共享。如果在一個程序文件中有多個函數(shù),在每一個函數(shù)中都可以改變?nèi)肿兞康闹?#xff0c;全局變量的值為各函數(shù)共享。但是用全局變量時安全性得不到保證,由于在各處都可以自由地修改全局變量的值,很有可能偶一失誤,全局變量的值就被修改,導致程序的失敗。因此在實際工作中很少使用全局變量。如果想在同類的多個對象之間實現(xiàn)數(shù)據(jù)共享,也不要用全局對象,可以用靜態(tài)的數(shù)據(jù)成員。
1、靜態(tài)數(shù)據(jù)成員
靜態(tài)數(shù)據(jù)成員是一種特殊的數(shù)據(jù)成員。它以關(guān)鍵字static開頭。
靜態(tài)數(shù)據(jù)成員定義一般形式:
static 數(shù)據(jù)類形靜態(tài)數(shù)據(jù)成員
靜態(tài)數(shù)據(jù)成員賦值一般形式:
數(shù)據(jù)類型類名::靜態(tài)數(shù)據(jù)成員名=初值;//只能在類體外進行初始化。
靜態(tài)數(shù)據(jù)成員引用一般形式:
類名::靜態(tài)數(shù)據(jù)成員名 // 通過類名引用靜態(tài)數(shù)據(jù)成員
對象.靜態(tài)數(shù)據(jù)成員名 //通過對象名引用靜態(tài)數(shù)據(jù)成員
例:
class Box
{public:
int volume();
private:
static int height;//把height定義為靜態(tài)的數(shù)據(jù)成員
int width;
int length; };
例10 引用靜態(tài)數(shù)據(jù)成員。
#include <iostream>
using namespace std;
class Box
{public:
Box(int,int);
int volume();
static int height; //把height定義為公用的靜態(tài)的數(shù)據(jù)成員
int width;
int length; };
Box::Box(int w,int len) //通過構(gòu)造函數(shù)對width和length賦初值
{width=w;
length=len; }
int Box::volume()
{return(height*width*length); }
int Box::height=10;//對靜態(tài)數(shù)據(jù)成員height初始化
int main()
{Box a(15,20),b(20,30);
cout<<a.height<<endl; //通過對象名a引用靜態(tài)數(shù)據(jù)成員
cout<<b.height<<endl; //通過對象名b引用靜態(tài)數(shù)據(jù)成員
cout<<Box::height<<endl; //通過類名引用靜態(tài)數(shù)據(jù)成員
cout<<a.volume()<<endl; //調(diào)用volume函數(shù),計算體積,輸出結(jié)果
return 0; }
說明:
(1)如果只聲明了類而未定義對象,則類的一般數(shù)據(jù)成員是不占內(nèi)存空間的,只有在定義對象時,才為對象的數(shù)據(jù)成員分配空間。靜態(tài)數(shù)據(jù)成員不屬于某一個對象,在為對象所分配的空間中不包括靜態(tài)數(shù)據(jù)成員所占的空間。靜態(tài)數(shù)據(jù)成員是在所有對象之外單獨開辟空間。只要在類中定義了靜態(tài)數(shù)據(jù)成員,即使不定義對象,也為靜態(tài)數(shù)據(jù)成員分配空間,它可以被引用。
在一個類中可以有一個或多個靜態(tài)數(shù)據(jù)成員,所有的對象共享這些靜態(tài)數(shù)據(jù)成員,都可以引用它。
(2)靜態(tài)數(shù)據(jù)成員不隨對象的建立而分配空間,也不隨對象的撤銷而釋放(一般數(shù)據(jù)成員是在對象建立時分配空間,在對象撤銷時釋放)。靜態(tài)數(shù)據(jù)成員是在程序編譯時被分配空間的,到程序結(jié)束時才釋放空間。
(3)靜態(tài)數(shù)據(jù)成員可以初始化,但只能在類體外進行初始化。
注意:不能用參數(shù)初始化表對靜態(tài)數(shù)據(jù)成員初始化。如在定義Box類中這樣定義構(gòu)造函數(shù)是錯誤的:
Box(int h,int w,int len):height(h){} //錯誤,height是靜態(tài)數(shù)據(jù)成員如果未對靜態(tài)數(shù)據(jù)成員賦初值,則編譯系統(tǒng)會自動賦予初值0。
(4)靜態(tài)數(shù)據(jù)成員既可以通過對象名引用,也可以通過類名來引用。
注意:在上面的程序中將height定義為公用的靜態(tài)數(shù)據(jù)成員,所以在類外可以直接引用,可以看到在類外可以通過對象名引用公用的靜態(tài)數(shù)據(jù)成員,也可以通過類名引用靜態(tài)數(shù)據(jù)成員
如上例中:a.height//通過對象名a引用靜態(tài)數(shù)據(jù)成員。
Box:: height//通過
如果靜態(tài)數(shù)據(jù)成員被定義為私有的,則不能在類外直接引用,而必須通過公用的成員函數(shù)引用。
(5)有了靜態(tài)數(shù)據(jù)成員,各對象之間的數(shù)據(jù)有了溝通的渠道,實現(xiàn)數(shù)據(jù)共享,因此可以不使用全局變量。全局變量破壞了封裝的原則,不符合面向?qū)ο蟪绦虻囊蟆?/span>
(6)公用靜態(tài)數(shù)據(jù)成員與全局變量的不同,靜態(tài)數(shù)據(jù)成員的作用域只限于定義該類的作用域內(nèi)(如果在一個函數(shù)中定義類,那么其中靜態(tài)數(shù)據(jù)成員的作用域就是此函數(shù)內(nèi))。在此作用域內(nèi),可以通過類名和域運算符"::"引用靜態(tài)數(shù)據(jù)成員,而不論類對象是否存在。
2、靜態(tài)成員函數(shù)
靜態(tài)成員函數(shù)定義一般形式:
static 數(shù)據(jù)類型靜態(tài)成員函數(shù)
靜態(tài)數(shù)據(jù)成員函數(shù)引用一般形式:
類名::靜態(tài)函數(shù)成員名// 通過類名引用靜態(tài)數(shù)據(jù)成員
對象.靜態(tài)函數(shù)成員名 //通過對象名引用靜態(tài)數(shù)據(jù)成員
作用:
與靜態(tài)數(shù)據(jù)成員不同,靜態(tài)成員函數(shù)的作用不是為了對象之間的溝通,而是為了能處理靜態(tài)數(shù)據(jù)成員。
靜態(tài)成員函數(shù)與非靜態(tài)成員函數(shù)的根本區(qū)別是:
非靜態(tài)成員函數(shù)有this指針,而靜態(tài)成員函數(shù)沒有this指針。由此決定了靜態(tài)成員函數(shù)不能訪問本類中的非靜態(tài)成員數(shù)據(jù)。
說明:
靜態(tài)成員函數(shù)可以直接引用本類中的靜態(tài)數(shù)據(jù)成員,因為靜態(tài)數(shù)據(jù)成員同樣是屬于類的,可以直接引用。在程序中,靜態(tài)成員函數(shù)主要用來訪問靜態(tài)數(shù)據(jù)成員,而不訪問非靜態(tài)成員。并不是絕對不能引用本類中的非靜態(tài)成員,只是不能進行默認訪問,因為無法知道應該去找哪個對象。如果一定要引用本類的非靜態(tài)成員,應該加對象名和成員運算符"."。
例11 靜態(tài)成員函數(shù)的應用。
#include <iostream>
using namespace std;
class Student //定義Student類
{public:
Student(int,int,int); //定義構(gòu)造函數(shù)
void total();
static float average(); //聲明靜態(tài)成員函數(shù)
private:
int num;
int age;
float score;
static float sum; //靜態(tài)數(shù)據(jù)成員
static int count;}; //靜態(tài)數(shù)據(jù)成員
Student::Student(int m,int a,int s)
{num=m;
age=a;
score=s; }
void Student::total() //定義非靜態(tài)成員函數(shù)
{ sum+=score; //累加總分
count++; } //計已統(tǒng)計的人數(shù)
Static float Student::average() //定義靜態(tài)成員函數(shù)
{ return(sum/count); } //使用靜態(tài)數(shù)據(jù)成員
float Student::sum=0; //對公用靜態(tài)數(shù)據(jù)成員初始化
int Student::count=0; //對公用靜態(tài)數(shù)據(jù)成員初始化
int main()
{Student stud[3]={ //定義對象數(shù)組并初始化
Student(1001,18,70),
Student(1002,19,79),
Student(1005,20,98) };
int n;
cout<<"please input the number of students:";
cin>>n; //輸入需要求前面多少名學生的平均成績
for(int i=0;i<n;i++) //調(diào)用n次total函數(shù)
stud[i].total();
cout<<"The average score of "<<n<<" students is "<<stud[0].average()<<endl;//使用對象名調(diào)用靜態(tài)成員函數(shù),也可通過類名調(diào)用:Student::average()
return 0; }
運行結(jié)果為
please inputthe numberOfstudents:3/
the average score of3 students is 82.3333
說明:
(1)在主函數(shù)中定義了stud對象數(shù)組,為了使程序簡練,只定義它含3個元素,分別存放3個學生的數(shù)據(jù)(每個學生的數(shù)據(jù)包括學號、年齡和成績)。程序的作用是先求用戶指定的n名學生的總分,然后求平均成績(n由用戶輸入)。
(2)在Student類中定義了兩個靜態(tài)數(shù)據(jù)成員sum(總分)和count(累計需要統(tǒng)汁的學生人數(shù)),這是由于這兩個數(shù)據(jù)成員的值是需要進行累加的,它們并不是只屬于某一個對象元素,而是由各對象元素共享的,可以看出:它們的值是在不斷變化的,而且無論對哪個對象元素而言,都是相同的,而且始終不釋放內(nèi)存空間。
(3)total是公有的成員函數(shù),其作用是將一個學生的成績累加到snm中。公有的成員函數(shù)可以引用本對象中的一般數(shù)據(jù)成員(非靜態(tài)數(shù)據(jù)成員),也可以引用類中的靜態(tài)數(shù)據(jù)成員。score是非靜態(tài)數(shù)據(jù)成員,sum和count是靜態(tài)數(shù)據(jù)成員。
(4)average是靜態(tài)成員函數(shù),它可以直接引用私有的靜態(tài)數(shù)據(jù)成員(不必加類名或?qū)ο竺?/span>),函數(shù)返回成績的平均值
(5)在main函數(shù)中,引用total函數(shù)要加對象名(今用對象數(shù)組元素名),引用靜態(tài)成員函數(shù)average函數(shù)要用類名或?qū)ο竺?/span>
(6)請思考:如果不將average函數(shù)定義為靜態(tài)成員函數(shù)行不行?程序能否通過編譯?需要作什么修改?為什么要用靜態(tài)成員函數(shù)?請分析其理由。
(7)如果想在average函數(shù)中引用stud[l]的非靜態(tài)數(shù)據(jù)成員score,應該怎樣處理?
有人在上面的程序基礎上將靜態(tài)成員函數(shù)average改寫為
float Student::average() //定義靜態(tài)成員函數(shù)
{cout<<stud[1].score<<endl; //引用非靜態(tài)數(shù)據(jù)成員
return(sum/count);}
結(jié)果發(fā)現(xiàn)在編譯時出錯。可以將average函數(shù)的定義改為
floatStudent::average(Studentstu) //函數(shù)參數(shù)為對象
{cout<<stu.score<<endl;//通過對象名引用非靜態(tài)數(shù)據(jù)成員
return(sum/count);
以上是在例11基礎上順便說明靜態(tài)成員函數(shù)引用非靜態(tài)數(shù)據(jù)成員的方法,以幫助理解。但是在程序中最好養(yǎng)成這樣的習慣:只用靜態(tài)成員函數(shù)引用靜態(tài)數(shù)據(jù)成員,而不引用非靜態(tài)數(shù)據(jù)成員。這樣思路清晰,邏輯清楚,不易出錯。
三、友元
友元定義:友元可以訪問與其有好友關(guān)系的類中的私有成員。友元包括友元函數(shù)和友元類。
定義格式:friend 友元函數(shù)和友元類
友元說明:在一個類中可以有公用的(public)成員和私有的(pnvate)成員,我們曾用客廳比喻公用部分,用臥室比喻私有部分。在類外可以訪問公用成員,只有本類中的函數(shù)可以訪問本類的私有成員。現(xiàn)在,我們來補充介紹——個例外——友元(friend)。
1、友元函數(shù)
如果在本類以外的其他地方定義了一個函數(shù)(這個函數(shù)可以是不屬于任何類的非成員函數(shù),也可以是其他類的成員函數(shù)),在對本類進行聲明時在類體中用friend對該函數(shù)進行聲明,此函數(shù)就稱為本類的友元函數(shù)。一個類的友元函數(shù)可以訪問這個類中的私有成員。
①將普通函數(shù)聲明為友元函數(shù)
通過下面的例子可以了解友元函數(shù)的性質(zhì)和作用。
例12 友元函數(shù)的簡單例子。
#include <iostream>
using namespace std;
class Time
{public:
Time(int,int,int);
friend void display(Time &); //聲明display函數(shù)為Time類的友元函數(shù)
private: //以下數(shù)據(jù)是私有數(shù)據(jù)成員
int hour;
int minute;
int sec; };
Time::Time(int h,int m,int s) //定義構(gòu)造函數(shù),給hour,minute,sec賦初值
{hour=h;
minute=m;
sec=s; }
void display(Time &t) //這是友元函數(shù),形參t是Time類對象的引用
{ cout<<t.hour<<":"<<t.minute<<":"<<t.sec<<endl; }
int main()
{ Time t1(10,13,56);
display(t1); //調(diào)用display函數(shù),實參t1是Time類對象
return 0; }
程序輸出結(jié)果如下:10:23:56
注意:
1、 display是一個在類外定義的且未用類Time作限定的函數(shù),它是非成員函數(shù),不屬于任何類。它的作用是輸出時間(時、分、秒)。如果在Time類的定義體中未聲明display函數(shù)為friend函數(shù),它是不能引用Time中的私有成員hour,minute,sec。
2、由于聲明了display是Time類的friend函數(shù),所以display函數(shù)可以引用Time中的私有成員hour,minute,sec。但注意在引用這些私有數(shù)據(jù)成雖時,必須加上對象名。因為display函數(shù)不是Time類的成員函數(shù),不能默認引用Time類的數(shù)據(jù)成員,必須指定要訪問的對象。
②友元成員函數(shù)
friend函數(shù)不僅可以是一般函數(shù)(非成員函數(shù)),而且可以是另一個類中的成員函數(shù)。
例13 友元成員函數(shù)的簡單應用。
在本例中除了介紹有關(guān)友元成員函數(shù)的簡單應用外,還將用到類的提前引用聲明,請讀者注意。請閱讀下面的程序:
#include <iostream>
using namespace std;
class Date; //對Date類的提前引用聲明
class Time //定義Time類
{public:
Time(int,int,int);
void display(const Date&);//display是成員函數(shù),形參是Date類對象的引用
private:
int hour;
int minute;
int sec; };
class Date //聲明Date類
{public:
Date(int,int,int);
friend void Time::display(const Date &);//聲明Time類中的display函數(shù)為本類的友元成員函數(shù)
private:
int month;
int day;
int year; };
Time::Time(int h,int m,int s)//定義類Time的構(gòu)造函數(shù)
{ hour=h;
minute=m;
sec=s; }
void Time::display(const Date &da) //display函數(shù)的作用是輸出年、月、日和時、分、秒
{cout<<d.month<<"/"<<d.day<<"/"<<d.year<<endl;//引用Date類對象中私有數(shù)據(jù)
cout<<hour<<":"<<minute<<":"<<sec<<endl; } //引用本類對象中的私有數(shù)據(jù)
Date::Date(int m,int d,int y) //類Date的構(gòu)造函數(shù)
{month=m;
day=d;
year=y; }
int main()
{ Time t1(10,13,56); //定義Time類對象t1
Date d1(12,25,2004); //定義Date類對象dl
t1.display(d1); //調(diào)用tl中的display函數(shù),實參是Date類對象dl
return 0; }
運行時輸出:
12/25/2004 (輸出Date類對象dl中的私有數(shù)據(jù))
l0:13:56 (輸出Time類對象11中的私有數(shù)據(jù))
注意在本程序的主函數(shù)中調(diào)用友元函數(shù)防問有關(guān)類的私有數(shù)據(jù)方法:
(1)在函數(shù)名display的前面要加display所在的對象名(t1);
(2)display成員函數(shù)的實參是Date類對象d1,否則就不能訪問對象dl中的私有數(shù)據(jù);
(3)在Time::display函數(shù)中引用Date類私有數(shù)據(jù)時必須加上對象名,如d.month。
③一個函數(shù)(包括普通函數(shù)和成員函數(shù))可以被多個類聲明為"朋友",這樣就可以引用多個類中的私有數(shù)據(jù)
2、友元類
聲明友元類的一般形式為:friend 類名;
例:在A類的定義體中用以下語句聲明B類為其友元類:
friend B:
說明:
1、友元的關(guān)系是單向的而不是雙向的。如果聲明了B類是A類的友元類,不等于A類是B類的友元類,A類中的成員函數(shù)不能訪問B類中的私有數(shù)據(jù)。
2、友元的關(guān)系不能傳遞,
友元利弊的分析:
面向?qū)ο蟪绦蛟O計的一個基本原則是封裝性和信息隱蔽,而友元卻可以訪問其他類中的私有成員,不能不說這是對封裝原則的一個小的破壞。但是它能有助于數(shù)據(jù)共享,能提高程序的效率,在使用友元時,要注意到它的副作用,不要過多地使用友元,只有在使用它能使程序精練,并能大大提高程序的效率時才用友元。也就是說,要在數(shù)據(jù)共享與信息隱蔽之間選擇一個恰當?shù)钠胶恻c。
四、類模板
允許使用函數(shù)模板,對于功能相同而數(shù)據(jù)類型不同的一些函數(shù),不必一一定義各個函數(shù),可以定義一個可對任何類型變量進行操作的函數(shù)模板,在調(diào)用函數(shù)時,系統(tǒng)會根據(jù)實參的類型,取代函數(shù)模板中的類型參數(shù),得到具體的函數(shù)。這樣可以簡化程序設計。
類模板一般定義形式:
template <class虛擬類型參數(shù)>//聲明一個模板,虛擬類型名為numtype
class 類模板名
{ 類體定義 }
請將此類模板和類定義作一比較,可以看到有兩處不同:
(1)聲明類模板時要增加一行: template<class虛擬類型參數(shù)>
(2)原有的類型名換成虛擬類型參數(shù)名numtype。在建立類對象時,如果將實際類型指定為int型,編譯系統(tǒng)就會用int取代所有的numtype,如果指定為float型,就用float取代所有的numtype。這樣就能實現(xiàn)"一類多用"。
(3)由于類模板包含類型參數(shù),因此又稱為參數(shù)化的類。如果說類是對象的抽象,對象是類的實例,則類模板是類的抽象,類是類模板的實例。利用類模板可以建立含各種數(shù)據(jù)類型的類。
(4)類模板的引用:類模板名<實際類型名> 對象名(實參表列);
例14 聲明一個類模板,利用它分別實現(xiàn)兩個整數(shù)、浮點數(shù)和字符的比較,求出大數(shù)和小數(shù)。
#include <iostream>
using namespace std;
template<class numtype> //定義類模板
class Compare
{public:
Compare(numtype a,numtype b)
{x=a;y=b;}
numtype max()
{return (x>y)?x:y;} //引用C語言中條件運算符
numtype min()
{return (x<y)?x:y;}
private:
numtype x,y; };
int main()
{ Compare<int> cmp1(3,7); //定義對象cmpl,用于兩個整數(shù)的比較
cout<<cmp1.max()<<" is the Maximum of two inteder numbers."<<endl;
cout<<cmp1.min()<<" is the Minimum of two inteder numbers."<<endl<<endl;
Compare<float> cmp2(45.78,93.6); //定義對象cmp2,用于兩個浮點數(shù)的比較
cout<<cmp2.max()<<" is the Maximum of two float numbers."<<endl;
cout<<cmp2.min()<<" is the Minimum of two float numbers."<<endl<<endl;
Compare<char> cmp3('a','A');//定義對象cmp3,用于兩個字符的比較
cout<<cmp3.max()<<" is the Maximum of two characters."<<endl;
cout<<cmp3.min()<<" is the Minimum of two characters."<<endl;
return 0;}
運行結(jié)果如下:
7 is the Maximum Of two integers
3 is the Minimum Of two integers.
93.6 is the Maximum Of two float numbers.
45.78 is the Minimum OftWO float numbers.
a is the Maximum Of two characters.
A is the Minimum Of two characters.
可以這樣聲明和使用類模板:
(1)先寫出一個實際的類(如本節(jié)開頭的Compare int)。由于其語義明確,含義清楚,一般不會出錯。
(2)將此類中準備改變的類型名(如int要改變?yōu)?/span>float或char)改用一個自己指定的虛擬類型名(如上例中的numtype)。
(3)在類聲明前面加入一行,格式為
template<class虛擬類型參數(shù)>
如 template<classnumtype> //注意本行末尾無分號
class Compare
{…};//類體
(4)用類模板定義對象時用以下形式:
類模板名<實際類型名>對象名;
類模板名<實際類型名> 對象名(實參表列);
(5)如果在類模板外定義成員函數(shù),應寫成類模板形式:
template<class虛擬類型參數(shù)>
函數(shù)類型類模板名<虛擬類型參數(shù)>::成員函數(shù)名(函數(shù)形參表列){…}
說明:
(1)類模板的類型參數(shù)可以有一個或多個,每個類型前面都必須加class,如
template<class Tl,class T2>
class someclass
{…};
在定義對象時分別代人實際的類型名,如
someelass<int,double> obj;
(2)和使用類一樣,使用類模板時要注意其作用域,只能在其有效作用域內(nèi)用它定義對象。如果類模板是在A文件開頭定義的,則A文件范圍內(nèi)為有效作用域,可以在其中的任何地方使用類模板,但不能在B文件中用類模板定義對象。
(3)模板可以有層次,一個類模板可以作為基類,派生出派生模板類。
轉(zhuǎn)載于:https://www.cnblogs.com/bluestorm/archive/2012/12/14/2818711.html
總結(jié)
以上是生活随笔為你收集整理的对象的赋值和复制(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Strut2的属性驱动,模型驱动的理解
- 下一篇: 2012年度IT博客大赛10强花落谁家暨