2010-04-28 71 views
3

有人能解釋爲什麼頭文件有這樣的東西?class foo;在頭文件

class foo; // This here? 
class bar 
{ 
    bar(); 

}; 

你使用這個時候需要一個包含語句?

謝謝。

回答

10

第一個class foo;被稱爲foo類的forward declaration。它只是讓編譯器知道它存在並且它命名了一個類。這使得foo被稱爲「不完整類型」(除非已經看到foo的完整聲明)。使用不完整的類型,您可以聲明該類型的指針,但不能分配該類型的實例或執行任何需要了解其大小或成員的任何事情。

這樣的前向聲明經常被使用,當兩種類型的每一種可能都有指向對方的指針時,在這種情況下,兩者都需要能夠表達指向其他類型的指針的概念,所以你將會有一個循環依賴這樣的事情。這主要是因爲C++使用單通機制來解析類型;在Java中,您可以擁有循環依賴關係而無需前向聲明,因爲Java使用多次傳遞。您還可以看到作者被誤導的印象中的前向聲明,即使用前向聲明而不是包含所需的頭部會減少編譯時間;當然,情況並非如此,因爲無論如何,您都需要包含完整的聲明(即頭文件),並且如果使用了預處理器警衛,那麼編譯時間基本上沒有區別。

要回答你是否需要在包括或不你的問題......假設你只需要一個部分的類型,那麼你的頭並不需要直接包括已向前聲明的類型頭;然而,誰利用你的頭的,當他們使用你的類型將需要包括前聲明的類型頭,所以你可能也僅僅包括其他的頭。

+0

+1。一些次要問題:你稱之爲「全面聲明」實際上是一個「定義」。 – sellibitze 2010-04-28 13:02:31

2

這是一個forward declaration。例如,如果class bar具有指向foo對象的指針,但不想立即包含foo對象的整個定義,則需要它。

0

這是一個前向聲明。請看下面的例子:

​​

如果您還沒有的class foo的定義使得編譯器在編譯的class bar代碼將無法編譯定義之前看到它(編譯器會說沒有關係」你不知道什麼foo的意思),除非你有前向聲明。

+0

的定義是沒有必要的。聲明就夠了。你的例子顯示了foo的聲明。 – sellibitze 2010-04-28 13:08:57

1

這是該類的前向聲明。 根據我的經驗,當你有一個循環依賴,這是典型的做法。例如

in foo.h 
-------- 
#include "bar.h" 

class foo 
{ 
public: 
    foo(bar *bar); 
private: 
    foo *m_foo; 
}; 

and in bar.h 
------------ 
class foo; 
class bar 
{ 
public: 
    void methodFooWillCall(); 
protected: 
    std::list<foo *> myFoos; 
} 
0

它的類「富」的向前聲明。它允許你聲明指針和對類的引用,但不是它使用它(例如,調用成員或確定其大小),因爲它尚未定義!之後必須進行完整的正常聲明(class foo { ... };)。

這對於聲明兩個彼此保持指針的類非常有用,否則這些指針將無法設置。

+0

你所謂的「正常聲明」是一個定義 – sellibitze 2010-04-28 13:06:01

0

這被稱爲前向聲明。類foo的主體將在文件的後面部分定義。前向聲明是爲了解決循環依賴性:類Bar的定義需要類Foo,反之亦然。

class Bar 
{ 
    Foo * foo; 
}; 
class Foo 
{ 
    Bar * bar; 
}; 

正如你所看到的,BarFoo,反之亦然參考。如果你試圖編譯這個,編譯器會投訴說它不知道Foo的任何內容。解決的辦法是轉發聲明Bar(就像你聲明main上述函數的原型,以後再定義它的身體)以上class Foo

class Foo; //Tells the compiler that there is a class Foo coming down the line. 
class Bar 
{ 
    Foo * foo; 
}; 
class Foo 
{ 
    Bar * bar; 
}; 
0

這被稱爲前向聲明。它用於使您的代碼意識到foo類存在。這反過來可以被類吧使用。

通常用它來解決圓形包括問題。藉此例如

//a.h 
#include "b.h" 

class A 
{ 
    void useB(B obj); 
} 

// b.h 
#include "a.h" 
class B 
{ 
    void useA(A obj); 
} 

這導致圓形包括問題,因爲A.H包括b.h這又包括A.H,爲無窮大。您可以通過在每個標題中的每個類的前向聲明解決這個問題,比如:

//a.h 
class B; 

class A 
{ 
    void useB(B obj); 
} 

// b.h 
class A; 

class B 
{ 
    void useA(A obj); 
} 

注:很多時候,當你有一個圓形包括問題,這是表明一個概念/建模問題。在嘗試用前向聲明解決您的問題之前,您應該問問自己,您的類是否已經定義好了。

1

只是好奇,爲什麼我們需要術語向前聲明呢?前向聲明不是簡單的聲明(而是定義)?

class X; // declaration 

class X // definition 
{ 
    int member; 
    void function(); 
}; 
+0

+1。是的。 :-) – sellibitze 2010-04-28 13:03:41

0

再想想寫這個的:

文件bar.h:

 #include "bar.h" 

     class Foo 
     { 
     Bar* bar_ptr; 
     } 

文件foo.h中:

 #include "foo.h" 

     class Bar 
     { 
      Foo* foo_ptr; 
     } 

這是行不通的,因爲第一無限的#include鏈,那麼如果你擺脫了其中一個包含,那麼Foo不會知道Bar是什麼,或者Bar不知道Foo是什麼。

試試這個:

 class Bar; 

     class Foo 
     { 
     Bar* bar_ptr; 
     }; 

文件foo.h中:

 class Foo; 

     class Bar 
     { 
      Foo* foo_ptr; 
     };