????????可以使用友元成員函數。在本例中除了介紹有關友元成員函數的簡單應用外,還將用到類的提前引用聲明,請讀者注意。
編寫程序:
運行結果:
程序分析:
????????在一般情況下,兩個不同的類是互不相干的。display函數是Time類中的成員函數,它本來只可以用來輸出Time類對象中的數據成員hour,minute,sec。現在在Date類中把它聲明為"朋友",因此也可以訪問Date類對象中的數據成員mouth,day,year。所以在display函數中既可以輸出Time類的時、分、秒,又可以輸出其"朋友"類的對象中的年、月、日。注意,在輸出本類對象的時、分、秒時,不必使用對象名,而在輸出Date類的對象中的年、月、日時,就必須加上對象名(如d.month)。如果不用友元函數,為了實現題目要求,就要在兩個類中分別包括兩個輸出函數(如display1,display2),在主函數中分別調用這兩個函數,先后輸出日期和時間。顯然用友元函數方便。
????????請注意在本程序中調用友元函數訪問有關類的私有數據方法:
????????(1)在函數名display的前面要加display所在的對象名(如t1)。
????????(2)display 成員函數的實參是Date類對象d1,否則就不能訪問對象d1中的私有數據。
????????(3)在Time::display函數中引用Date類私有數據時必須加上對象名,如d.month。
注意:在本例中聲明了兩個類Time和Date。程序第3行是對Date類的聲明,因為在第7行和第16行中對display函數的聲明和定義中要用到類名Date,而對Data類的定義卻在其后面。能否將Date類的聲明提到前面來呢?也不行,因為在 Date類中第 4行又用到了Time類,也要求先聲明Time類才能使用它。這就形成了"連環套",類似于"雞生蛋,蛋生雞"的問題。為了解決這個問題,C++允許對類進行"提前引用"的聲明,即在正式聲明一個類之前,先聲明一個類名,表示此類將在稍后聲明。程序第3行就是提前引用聲明,它只包含類名,不包括類體。如果沒有第3行,程序編譯就會出錯。有了第3行,在編譯時,編譯系統會從中得知 Date是一個類名,此類將在稍后定義。
????????有關對象提前引用的知識:在一般情況下,對象必須先聲明,然后才能使用它。但是在特殊情況下(如本例所示的這樣),在正式聲明類之前,需要使用該類名。但是應當注意:類的提前聲明的使用范圍是有限的。只有在正式聲明一個類以后才能用它去定義類對象。如果在上面程序第3行后面增加一行:
????????Date d1;? ? ? ? //試圖定義一個對象
會在編譯時出錯。因為在定義對象時是要為這些對象分配存儲空間的,在正式聲明類之前,編譯系統無法確定應為對象分配多大的空間。編譯系統只有在"見到"類體后,才能確定應該為對象預留多大的空間。在對一個類做了提前引用聲明后,可以用該類的名字去定義指向該類型對象的指針變量或對象的引用(如在本例中,display的形參是Date類對象的引用)。這是因為指針變量和引用與它所指向的類對象的大小無關。
????????請注意程序是在定義Time::display函數之前正式聲明Date類的。如果將對Date類的聲明的位置(程序第13~21行)改到定義Time::display函數之后,編譯就會出錯,因為在Time::display函數體中要用到Date類的成員month,day,year。如果不事先聲明Date類,編譯系統無法識別成員 month,day,year等成員。讀者可以上機調試一下。
????????說明: 一個函數( 包據普通函數和成員函數)可以被多個類聲明為"朋友",這樣就可以引用多個類中的私有數據。