C++ Trick:什麼時候需要前置聲明?

經常有C++開發的小夥伴提問:

C++中要使用類A時,什麼時候#include "a.h",什麼時候用class A前置聲明呢?

通常來說,你都不需要主動去寫class A這種前置聲明。include能編譯通過的時候都不要去寫前置聲明,應該僅當出現了頭文件循環依賴導致編譯失敗的時候,纔去考慮去寫前置聲明!

頭文件循環依賴,就是說兩個頭文件互相include了對方,這樣編譯會出問題。舉個例子。

有a.h(裏面用了類型B的指針,所以include了b.h):

#pragma once

#include "b.h"
class A {
public:
    A():_b(nullptr) {}
    ~A() {}

    void set_b(B* b) {
        _b = b;
    }
    B* get_b() {
        return _b;
    }

private:
    B* _b;
};

有b.h:

#pragma once
#include "a.h"

class B {
public:
    B(int i):_i(i) {}
    ~B() {}

    int i() {
        return _i;
    }

    void foo(A& a) {
        B* b = a.get_b();
        b->_i += _i;
    }

private:
    int _i;
};

有main.cpp (包含main函數)

#include "a.h"
#include "b.h"
#include <iostream>
using namespace std;

int main() {
    A a;
    B b(3);
    a.set_b(&b);

    B b2(7);
    b2.foo(a);

    cout << a.get_b()->i() << endl;
    return 0;
}

編譯main.cpp失敗,報錯:

./b.h:13:14: error: unknown type name 'A'
 void foo(A& a) {
 ^
1 error generated.

修改方法,因爲a.h中只出現了類型B的指針,而未調用其成員函數或成員變量,故可以修改a.h刪除include "b.h",增加類型B的前置聲明。

#pragma once

class B; // 前置聲明!
class A {
public:
    A():_b(nullptr) {}
    ~A() {}

    void set_b(B* b) {
        _b = b;
    }
    B* get_b() {
        return _b;
    }

private:
    B* _b;

};

編譯main.cpp通過。

當然前置聲明也不是萬能的解藥,請注意前面的加粗黑字:

因爲a.h中只出現了類型B的指針,而未調用其成員函數或成員變量,故……

換言之,如果a.h中使用了類型B的成員函數,則無法通過更改爲前置聲明的方式,來讓編譯通過。

比如:

#pragma once
#include <iostream>
class B;
class A {
public:
    A():_b(nullptr) {}
    ~A() {}

    void set_b(B* b) {
        std::cout<< b->i() << std::endl; // !使用了B的成員函數
        _b = b;
    }
    B* get_b() {
        return _b;
    }

private:
    B* _b;

};

編譯報錯:

./a.h:10:22: error: member access into incomplete type 'B'
        std::cout<< b->i() << std::endl;
                     ^
./a.h:3:7: note: forward declaration of 'B'
class B;

這時候只能老老實實地改代碼,重新梳理並設計類A和類B的關係!
看起來有點亂,記不住?其實不難理解,因爲對C++而言,不管是什麼指針,它的大小都是確定的。所以只要a.h中只是出現B的指針(或引用)而沒有調用其具體的成員函數,C++編譯器是可以不去在此時理解B的具體定義的(故只添加class B的聲明即可),一旦a.h中用到了B的成員函數,則不然。

以上就是本次分享的所有內容,想要了解更多歡迎前往公衆號:C語言學習聯盟,每日干貨分享

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章