靜態成員和友元_第1頁
靜態成員和友元_第2頁
靜態成員和友元_第3頁
靜態成員和友元_第4頁
靜態成員和友元_第5頁
已閱讀5頁,還剩21頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

靜態成員和友元引入考慮一個學生管理系統,有時候需要向系統添加一個學生,有時候需要從系統中刪除一個學生。我們希望能夠隨時顯示該系統中的所有學生,并且能夠隨時獲取系統中的學生總數。使用鏈表來存儲所有的學生。要求在一個常數時間內得到系統中的學生總數。第2頁,共28頁,2024年2月25日,星期天6.1靜態成員-背景使用類數據成員保存鏈表頭指針和學生總數的作法是不可取的,因為每個該類的對象都擁有一份副本,需要花費精力來維護這些副本的一致性(這些副本必須完全相同)。設置全局變量來保存鏈表頭指針和學生總數的作法可行,但是不夠安全,因為程序的任何地方都可以修改這兩個變量(導致程序的行為異常)。【演示】第3頁,共28頁,2024年2月25日,星期天6.1靜態成員-引入可以使用靜態成員解決上述問題。靜態成員包括兩種:靜態數據成員:使用關鍵字static修飾的數據成員。靜態成員函數:使用關鍵字static修飾的成員函數。補充:C語言中使用static關鍵字描述了變量或者函數的可見性。全局靜態變量/對象是只在當前源文件中可見的全局變量或者對象。示例不同源文件中可以定義同名的全局靜態變量,但是各自占用的內存不同。局部靜態變量/對象是只在函數局部作用域內可見的變量或者對象,其生存期等于程序的生存期。靜態函數是只在當前源文件中可見的函數。不同源文件中可以定義同名的靜態函數。示例第4頁,共28頁,2024年2月25日,星期天6.2靜態數據成員使用static關鍵字修飾數據成員。靜態數據成員不屬于該類的任何對象,而是由該類的所有對象共享。靜態數據成員是屬于類的,而不是屬于對象的。一個類的靜態數據成員只有一個,無論該類目前有多少個對象。公有的靜態數據成員可以在程序的任何地方訪問,非公有的靜態數據成員只能在類的作用域內或者友元中訪問。classStudent{

…private:charm_name[20];Student*m_pNext;Student*m_pPrev;

staticStudent*m_pListHead;};第5頁,共28頁,2024年2月25日,星期天6.2靜態數據成員-訪問在類的成員函數中可以直接訪問此類的靜態數據成員,無需使用任何成員訪問算符(.和->)。在非成員函數中可以以兩種方式訪問一個類的公有靜態數據成員。通過該類的對象,使用.和->算符訪問使用類名限定的成員名來訪問Student::Student(char*name):m_pNext(NULL),m_pPrev(NULL){

…//每構造一個對象,學生總

//數應該加1++s_nStudentCount;}Students(“aa”);Studentt(“bb”);cout<<s.s_nCount;//OKcout<<t.s_nCount;//OKcout<<Student::s_nCount;//OK//以下斷言成立assert(&s.s_nCount==&t.s_nCount);assert(&s.s_nCount==&Student::s_nCount);第6頁,共28頁,2024年2月25日,星期天6.2靜態數據成員-唯一性一個對象占用空間的大小和靜態數據成員大小無關,換句話說:一個對象占用空間的大小是由該類所有非靜態數據成員大小之和決定的。默認的拷貝構造行為會拷貝靜態成員嗎?靜態數據成員所占用的空間不會隨著對象的產生而分配,也不會隨著對象的銷毀而回收。靜態數據成員具有靜態生存期。靜態數據成員保存在程序的全局數據區中。在main函數開始運行之前就已經準備好了。在main函數返回之后結束其生存期。第7頁,共28頁,2024年2月25日,星期天classStudent{public:Student(char*name);~Student();private:charm_name[20];Student*m_pNext;Student*m_pPrev;

staticStudent*s_pListHead;};voidmain(){Student*p1=newStudent(“a”);Student*p2=newStudent(“b”);Student*p3=newStudent(“c”);…}Heap“aaaa”m_pNextm_pPrev“bbbb”m_pNextm_pPrev“cccc”m_pNextm_pPrev全局數據區s_pListHeadStackp3p2p1OS運行狀態第8頁,共28頁,2024年2月25日,星期天6.2靜態數據成員-初始化類定義中只是聲明了靜態數據成員的存在(不會為其分配空間),還需要定義該靜態數據成員(為其分配內存空間)。靜態數據成員的定義不能放在頭文件中,否則當多個源文件都包含該頭文件時,將產生重復定義的鏈接錯誤。靜態數據成員的定義應該放在源文件中。定義和初始化靜態數據成員的語法:<靜態數據成員類型><類名>::<靜態數據成員名>=<值>;<靜態數據成員類型><類名>::<靜態數據成員名>(<值>);第9頁,共28頁,2024年2月25日,星期天靜態成員的初始化//Student.hclassStudent{public:Student(char*name);~Student();private:charm_name[20];Student*m_pNext;Student*m_pPrev;

staticStudent*s_pListHead;staticint s_nCount;};//Student.cpp#include“student.h”Student*Student::s_pListHead=NULL;intStudent::s_nCount=0;Student::Student(char*name){

…}Student::~Student(){

…}第10頁,共28頁,2024年2月25日,星期天6.2靜態數據成員靜態數據成員的類型可以是其所屬類,而非靜態數據成員只能聲明為該類對象的指針或者引用。classStudent{public:

…private: staticStudents_leader;//OK Student*m_pLeader;//OK Studentm_leader;//ERROR};靜態數據成員從其行為上看和全局對象類似,但是使用靜態數據成員可以實現數據隱藏,靜態數據成員可以是private的,全局對象則不能。靜態數據成員不會和全局變量發生名字沖突。第11頁,共28頁,2024年2月25日,星期天6.2靜態數據成員-勘誤教材P335的例子前的描述是不準確的。如果說s.nextStudent未被執行,則程序運行的結果應該是0。實際上此段代碼在VC6,VC.NET中的運行結果都是1;在Dev-C++環境中的運行結果是0;說明不同的編譯器會對此段代碼產生不同的結果。所以在實際編程中,應該總是使用::的方式來訪問靜態數據成員。【演示3】第12頁,共28頁,2024年2月25日,星期天6.3靜態成員函數-引入使用static關鍵字修飾的成員函數。靜態成員函數和靜態數據成員類似,不屬于任何對象,而是屬于類的。只要類存在就可以使用其靜態成員函數,與該類當前是否創建過對象或者創建了幾個對象無關。靜態成員函數的定義和非靜態的成員函數定義一樣,在靜態成員函數定義時不能使用static。第13頁,共28頁,2024年2月25日,星期天//Student.hclassStudent{public:Student(char*name);~Student();char*GetName();

staticvoidPrintAllStudents();private:charm_name[20];Student*m_pNext;Student*m_pPrev;

staticStudent*m_pListHead;};//Student.cpp#include“student.h”Student*Student::m_pListHead=NULL;Student::Student(char*name){…}Student::~Student(){…}voidStudent::PrintAllStudents(){…}第14頁,共28頁,2024年2月25日,星期天6.3靜態成員函數-對象無關靜態成員函數不與任何對象相聯系,因而靜態成員函數沒有this指針,即調用靜態成員函數時不會隱含的傳遞this指針。因為靜態成員函數沒有this指針,所以靜態成員函數不能聲明為const。因為靜態成員函數沒有this指針,因此可以將其賦給一個函數指針。typedefvoid(*PROC)();PROCproc=Student::PrintAllStudent;第15頁,共28頁,2024年2月25日,星期天6.3靜態成員函數因為靜態成員函數沒有this指針,所以在靜態成員函數中不能直接訪問類的非靜態成員,而必須通過該類的一個對象使用成員訪問算法訪問類的非靜態成員。在靜態成員函數中可以直接訪問類的其他靜態數據成員或者靜態成員函數(無論其是否公有)。在非靜態成員函數中可以直接調用該類的靜態成員函數。第16頁,共28頁,2024年2月25日,星期天//Student.cpp#include“student.h”…voidStudent::PrintAllStudents(){//直接訪問靜態成員,OKStudent*q=s_pListHead;while(q!=NULL){//通過對象訪問公有非靜態成員,OKcout<<q->GetName()<<endl;//通過對象訪問私有非靜態成員,OKcout<<q->m_name<<endl;//通過對象訪問私有非靜態成員,OKq=q->m_pNext;}}//Student.hclassStudent{public:Student(char*name);~Student();char*GetName(){returnm_name;}

staticvoidPrintAllStudents();private:charm_name[20];Student*m_pNext;Student*m_pPrev;

staticStudent*m_pListHead;};第17頁,共28頁,2024年2月25日,星期天6.3靜態成員函數-調用在類的作用域外調用類的靜態成員函數有兩種途徑:通過對象使用成員訪問算符訪問。

Students;s.PrintAllStudent();通過類名限定的函數名訪問,建議使用該方式,因為這種方式的調用更加明確的說明了此函數的歸屬,也不會出現教材P335頁可能存在的問題。

Student::PrintAllStudents();靜態成員函數從其行為上看更象是普通函數。不過靜態成員函數定義于類的作用域中,因而能夠任意訪問類的非公有成員。普通函數則不能訪問類的非公有成員。第18頁,共28頁,2024年2月25日,星期天6.4示例-對演示1的改進使用靜態數據成員和靜態成員函數修改演示1的代碼。鏈表的頭指針和鏈表的長度設為靜態數據成員。將打印鏈表元素的函數設為Student類的靜態成員函數,從而使得PrintAllStudents從原來類功能的使用者變為了類功能的提供者。【演示】第19頁,共28頁,2024年2月25日,星期天6.4示例如何使一個類的對象只能在堆上建立?也就是說不能定義該類的全局對象,也不能定義該類的局部對象,而只能從堆中為對象分配內存。將構造函數聲明為私有可以防止類的使用者構造此類的對象,但是同時也禁止了從堆上構造對象。靜態成員函數能夠任意訪問此類的成員函數,包括構造函數。【演示】第20頁,共28頁,2024年2月25日,星期天6.4示例如何使一個類只能創建一個對象?將構造函數聲明為私有可以防止類的使用者構造此類的對象。靜態數據成員的類型可以是其所屬類。演示單件(Singleton)是編程中的慣用手法。如一個系統中的權限控制類第21頁,共28頁,2024年2月25日,星期天//a.cppstaticintg_nCount;//此變量只能在a.cpp中使用voidAddToList(Node*pHead,Node*pToInsert){

…++g_nCount;}voidRemoveFromList(Node*pHead,Node*pToDelete){

…--g_nCount;}//b.cpp//errorC2159:morethanonestorageclassspecifiedexternstaticintg_nCount;externintg_nCount;voidPrintListLength(){

//errorLNK2001:unresolvedexternalsymbol"intg_nCount"

cout<<g_nCount<<endl;}第22頁,共28頁,2024年2月25日,星期天//a.cppintg_nCount;static

voidAddToList(Node*pHead,Node*pToInsert)//只在a.cpp中使用{

…++g_nCount;}voidRemoveFromList(Node*pHead,Node*pToDelete){

…--g_nCount;}//b.cppstaticvoidAddToList(Node*pHead,Node*pToInsert);voidAddToList(Node*pHead,Node*pToInsert);voidRemoveFromList(Node*pHead,Node*pToDelete);voidmain(){

…AddToList(p,q);//errorC2129:staticfunctiondeclaredbutnotdefined}AddToList(p,q);//errorLNK2001:unresolvedexternalsymbol‘AddToList’第23頁,共28頁,2024年2月25日,星期天6.5友元在類的作用域外不能訪問一個類的非公有成員。類可以聲明一個普通函數、其他類的成員函數或者另一個類為其友元,從而向友元暴露所有非公有成員。由于友元不是類的成員,故類中聲明友元的位置不受成員訪問限定符的影響,可以在public區,也可以在private區,效果完全一樣。友元聲明主要用于運算符重載(后面的章節解釋)友元破壞了封裝性和數據隱藏,實際中應盡量少用或者不用。第24頁,共28頁,2024年2月25日,星期天6.5友元-普通函數一個類可以在其類定義中聲明某個普通函數為其友元,從而使該函數可以任意訪問其非公有成員。在類中使用friend關鍵字聲明友元函數,格式為:friend<類型><友元函數名>(<參數表>);教材P344頁下面的代碼存在一處語法錯誤,錯在哪里?使用友元實現矩陣和矢量的乘法。classMatrix;classVector{

friendVectorMultiply(Matrix&,Vector&);};classMatrix{…friendVectorMultiply(Matrix&,Vector&);};第

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論