2011-03-18 32 views
2

宣佈對象我具有低於一個簡單的代碼:問題的在C++

class B; 
class A{ 
    B b; 
}; 

class B{ 
public: 
    B(){ 

    } 
}; 

在A類的定義,我有一個B-類型屬性。使用MS Visual Studio來編譯,我有以下錯誤:

error C2079: 'A::b' uses undefined class 'B' 

由於某些原因,我不能把以前的A類的一個B級的定義。任何想法?

+3

你是什麼意思,說「有些原因」?這些原因是什麼? – 2011-03-18 10:22:40

+0

如果B類不需要定義類A - 先定義類B,然後定義A類。否則,你將被迫使用指針。 – rmflow 2011-03-18 10:27:15

+0

這裏的原因可以用「循環依賴」來解釋。請參閱http://en.wikipedia.org/wiki/Circular_dependency。所有我想要的是將2個類的聲明放在一個文件中。 :( – anhldbk 2011-03-19 03:50:46

回答

12

編譯器已經告訴你什麼是錯誤的:A有一個未定義類型的成員數據b。您的正向聲明:

class B; 

就是這樣:一個聲明,而不是一個定義。由於類A直接包含B的實例(不僅僅是指向B的指針),因此編譯器需要知道B的確切大小:它需要它的定義,而不僅僅是一個聲明,即在某個時刻B會存在的承諾。

在這裏做最簡單的事情是重新安排事情是這樣的:

class B{ 
public: 
    B(){ 

    } 
}; 

class A{ 
    B b; 
}; 

編輯:又見this question的聲明和定義的區別。

進一步編輯:另一種方法是將您的成員數據更改爲指針或引用。 請注意,這不是一個簡單的語法變化:它對您的對象的生命週期有影響,因爲A :: b指向的對象可以在A的銷燬後繼續存在。

如果您想要的是組成(B是A的一部分,並與A一起死亡),使用指針會使你的生活變得更加困難,收益甚微。

更多編輯(!):剛纔意識到我誤解了你的問題的結尾;有什麼理由阻止你在A之前宣佈B?

如果他們不能解決,你可能不得不去指針路線。這些原因可能是您的物體耦合過於緊密的標誌! (也許B需要成爲A的內部類,或者簡單地合併成單個對象?)

+0

感謝您的詳細解答!:) – anhldbk 2011-03-19 03:58:13

1
class A; 

class B { 
    A * getA(); 
}; 

class A { 
    B b; 
}; 

這是解決這個問題的典型方法。你必須有B的定義,以便有一個B b;成員。

你需要預先聲明,以聲明引用/指針B,你需要爲了做任何其他與B中的完整定義(如定義變量,調用一個成員函數等)

+1

OPs代碼中沒有循環依賴關係 – 2011-03-18 10:29:19

+0

@Space:不在他的示例中 - 雖然解釋仍然正確 – Erik 2011-03-18 10:42:34

1

如果將引用更改爲指向B的指針b,則可以執行此操作。

class A{ 
    B* bPtr; 
}; 

class B{ 
public: 
    B(){ 

    } 
}; 

原則上,你並不需要一個顯式聲明 - 也就是說,一個向前聲明是所有需要 - 當你不需要類的實際大小,或訪問到類中的類型和成員函數。

在您的原始示例中,您正在對B進行直接引用。因此,編譯器需要知道關於B的所有內容,因此需要顯式聲明而不是前向聲明。

通過使用A類聲明使用指向B的指針,那麼您可以使用前向聲明離開。

編輯

有些鏈接可能解釋的理念爲您:

​​

http://www-subatech.in2p3.fr/~photons/subatech/soft/carnac/CPP-INC-1.shtml

http://www.codeguru.com/forum/showthread.php?t=358333(見職位#2)

http://en.wikipedia.org/wiki/Forward_declaration

1

C++有一個「不完整」類的概念,它是你需要知道的。

使用不完整的類可以讓你在許多情況下只使用一個類,知道它是一個類,而不知道它是什麼。

這使得類詳細信息可以稍後更改,而不需要重新編譯,因此它是耦合模型中較弱的依賴關係。

你需要一個完整的類:

  • 有一個實例。
  • 從中派生
  • 調用它的任何方法。
  • 刪除指向它的指針。

你只需要一個不完整的類:

  • 持有的指針或引用。
  • 將指針或引用傳遞給一個帶有指針或引用的函數。 (這可以是一個刪除指針的函數,只要它在該點完全定義)。

我想你只需要一個完整的類來聲明返回一個函數,並可能宣佈一個函數,一個作爲參數,但在當時定義或調用它需要的是完整的功能即使你不使用返回值。