2012-08-16 183 views
0

代碼如下所示:派生類錯誤:未定義類型

class B {/*something*/}; 

class D1: public B { 
public: 
void set() = 0; 
friend int D2::get(D1&); 
private: 
int a; 
} 
class D2: public B { 
public: 
int get(D1& d) {return d.a;} 
} 

我已經包含在這兩個派生類的.h文件("D1.h" and "D2.h"),也有 「D2.h」 在D1,D2中"D1.h""B.h" .. 。但不斷收到編譯錯誤:

...\D2.h ... use of undefined type D1 

那麼我在做什麼錯了?謝謝。

回答

2

您創建了一個圓形夾雜:你包括D1.hD2.h,你還包括D2.hD1.h。循環包容從未起作用,從未達到任何目的。

你的循環包含是類定義之間循環依賴的直接後果。在你的代碼中,這兩個類的定義都是相互引用的,要求這兩個類的類型都是完整的(要完全定義)。這意味着無論你做什麼,你的代碼都是無法編譯的。您需要打破類定義之間的循環依賴關係。

在你的情況下,可以通過以下方式來完成。

保持D1.h不變,即將D2.h保持爲D1.h,並保持類D1的定義原樣。

然而,包括D1.hD2.h而是引入D1預先聲明爲D2.h

class D1; 

變化D2的定義

class D2: public B { 
public: 
    int get(D1& d); 
}; 

注意:不要試圖去定義方法get正確定義類D2。你必須搬遷D2::get定義一些其他的地方,那裏的D1完整定義也是可見的(就像D2.cpp例如,其中應包括D1.hD2.h

int D2::get(D1& d) 
{ 
    return d.a; 
} 

就是這樣。通過這種方式定義D2::get的副作用是它變爲非內聯。如果你真的想保持它內聯,你必須把它定義爲

inline int D2::get(D1& d) 
{ 
    return d.a; 
} 

,並確保它是某種只包括D1完整定義。例如,您可以將它放在第三個頭文件(D2_aux.h或類似的東西)中,並記住在之後包括它D1.h

當然,嘗試解決此問題的更好方法是重新考慮整個設計。你真的需要D1內的朋友聲明嗎?也許你應該以某種方式重新設計你的代碼,以消除這個朋友聲明的需要,從而消除這種依賴性。


或者,您也可以通過改變D1.h並保持D2.h不變解決。然而,跟着你將有一個更徹底的和寬鬆的

friend class D2; 

,以取代「細粒度」 friend聲明

friend int D2::get(D1&); 

D1.h去除D2.h列入該路徑。

前朋友聲明要求類D2是完整的,這實際上是創建「不可破壞」的依賴關係。後面的聲明不需要D2是完整的。

+0

感謝man ...'get()'的定義其實是最初的問題(但是不知道,那麼我在這兩個類中都包含了.h文件)。從來沒有想到這一點。 – scarably 2012-08-16 16:20:54

+0

不,實際上......我可以通過在D2內部創建'int get_d1(){return a}'和'int get(D1&x)'{{return x.get_d1();}'來重新設計代碼。 。但我認爲第一個版本更好? – scarably 2012-08-16 16:36:08

+0

stefaneli31:是的,這就是我所說的「重新思考設計」和「不需要朋友聲明」。 – AnT 2012-08-16 16:42:36

0

如果D1的定義取決於D2和D2的定義取決於D1,那麼你就需要轉發參考類:

class B; 
class D1; 
class D2; 
0

在點是代碼提到D2沒有發生過任何事情說什麼D2是(編譯器不希望弄清楚)。所以你需要通過在D1的定義開始之前加上class D2;來告訴編譯器什麼是D2

+0

您不能「轉發聲明」類類型以便稍後在引用其成員的朋友聲明中使用它們。在這種朋友聲明中使用的類類型必須是* complete *。在D1類定義之前添加一個前向聲明'class D2;'不會使D1中的朋友聲明有效。出於這個原因,解決這種情況(不重新設計類關係)的唯一方法是在'D2'之前轉發'D1',而不是相反。 – AnT 2012-08-16 16:31:19

+0

@安德烈 - 你說得對。我沒有仔細看。有關聲明是'D2 :: get(D1&)',編譯器知道該成員的唯一方法是看完整個類。請注意,如果你想讓整個班級成爲朋友,你**不需要完整的定義。只需轉發聲明類即可,或者即時提及它('朋友類X'),儘管如果您不瞭解名稱注入規則,後者可能會給您帶來不可思議的錯誤。 – 2012-08-16 16:38:43