C++ 前置定義 Forward declaration

SoloGala發表於2020-11-07

C++ 前置定義 Forward declaration

在編寫相對大型的CPP工程的時候,往往我們會遇到一個情況,即:

// A.hpp
#include "B.hpp"
class A{  
};
// B.hpp
#include "A.hpp"
class B{
};

這往往會觸發編譯器的報錯。為了解決這種迴圈引用標頭檔案的問題,我們可以使用c++的前置引用(forward declaration)。

// A.hpp
class B; // ** forward declaration **
class A{  
};
// B.hpp
#include "A.hpp"
class B{
};

我們選擇在相對比較基礎的標頭檔案中使用前置定義,定義出 class B, 這可以簡單理解為, 當編譯器在處理A.hpp的時候我們告訴了編譯器,這個B 雖然沒有出現在當前檔案的include 裡面,但是它之後會被建立。

Note

使用前置定義的時候也有需要注意的地方,分為以下幾點。

假設我們使用前置定義宣告瞭一個class, 通常我們稱這個類為incomplete type

class X;

可以的操作有:

What you can do with an incomplete type:

  • 作為成員型別,注意 此處只能宣告指標或者引用:

    class Foo {
        X *p;
        X &r;
    };
    
  • 定義函式,作為形參或者返回型別, 注意這裡的函式定義,與下面的函式宣告的區別,只有型別:

    void f1(X);
    X    f2();
    
  • 使用該型別的指標或者引用:

    void f3(X*, X&) {}
    X&   f4()       {}
    X*   f5()       {}
    

What you cannot do with an incomplete type:

  • 作為基類

    class Foo : X {} // compiler error!
    
  • 作為成員型別,宣告成員變數(因為我們不知道該型別的具體大小,記憶體分佈):

    class Foo {
        X m; // compiler error!
    };
    
  • 定義該型別的返回值或者形參, 這裡與上面的不同在於實現了 函式體。這往往會涉及到該型別的 拷貝建構函式 或者 賦值建構函式。

    void f1(X x) {} // compiler error!
    X    f2()    {} // compiler error!
    
  • 使用該型別的方法,或者成員變數。

    class Foo {
        X *m;            
        void method()            
        {
            m->someMethod();      // compiler error!
            int i = m->someField; // compiler error!
        }
    };
    

ref

相關文章