我們知道C++的類應當是先定義,然后使用。但在處理相對復雜的問題、考慮類的組合時,很可能遇到倆個類相互引用的情況,這種情況稱為循環依賴。
例如:
class A { public: void f(B b);//以B類對象b為形參的成員函數 //這里編譯錯位,因為'B'為為止符號 }; class B { public: void g(A a); };
這里類A的公有成員函數f的形參是類B的對象,同時類B的公有成員函數g也以類A的對象為形參。由於在使用一個類之前,必須首先定義該類,因此無論將哪一個類的定義放在前面,都會引起編譯錯誤。結局這個問題的方法,就是使用前向引用聲明。前向引用聲明,是在引用未定義的類之前,將該類的名字告訴編譯器,試編譯器知道那是一個類名。這樣,當程序中使用這個類名時,編譯器就不會認為是錯誤,而類的完整定義可以在程序的其他地方。在上述程序加上下面的前向引用聲明,問題就解決了。
class B; //前向引用聲明 class A//A類的定義 { public://外部接口 void f(B b);//以B類對象b為形參的成員函數 }; class B//B類的定義 { public://外部接口 void g(A a);//以A類對象a為形參的成員函數 };
使用前向引用聲明雖然可以解決一些問題,但它並不是萬能的。需要注意的是,盡管使用了前向引用聲明,
但是在提供一個完整的類聲明之前,不能定義該類的對象,也不能在內聯成員函數中使用該類的對象。請看下面的程序段:
class Fred; //前向引用聲明 class Barney { Fred x; //錯誤:類Fred的聲明尚不完善 }; class Fred { Barney y; };
編譯出錯的原因是對此類Fred的前向引用聲明只能說明Fred是一個類名,而不能給出該類的完整定義,因此在類Barney中不能定義類Fred的數據成員。
再看下面這一段程序:
class Fred; //前向引用聲明 class Barney { public: void method() { x->yabbaDabbaDo(); //錯誤:Fred類的對象在定義之前被使用 } private: Fred* x; //正確,經過前向引用聲明,可以聲明Fred類的對象指針 }; class Fred { public: void yabbaDabbaDo(); private: Barney* y; };
出錯原因:類Barney的內聯函數中使用了由x所指向、Fred類的對象,而此時Fred類尚未完整地定義。
應該記住:當你使用前向引用聲明時,你只能使用被聲明的符號,而不能涉及類的任何細節。
C++的類可以進行前向聲明。但是,僅僅進行前向聲明而沒有定義的類是不完整的,這樣的類,
只能用於定義指針、引用、以及用於函數形參的指針和引用。
而不能定義對象(因為此時編譯器只知道這是個類,還不知道這個類的大小有多大),也不能訪問類的對象,任何形式的訪問都不允許(因為此時根本不知道有些什么成員)。等到類正式定義以后,就可以以各種方式使用該類了。
而不能定義對象(因為此時編譯器只知道這是個類,還不知道這個類的大小有多大),也不能訪問類的對象,任何形式的訪問都不允許(因為此時根本不知道有些什么成員)。等到類正式定義以后,就可以以各種方式使用該類了。