關於C++中的前置聲明


原文http://patmusing.blog.163.com/blog/static/135834960201038113714199/

在編寫C++程序的時候,偶爾需要用到前置聲明(Forward declaration)。下面的程序中,帶注釋的那行就是類B的前置說明。這是必須的,因為類A中用到了類B,而類B的聲明出現在類A的后面。如果沒有類B的前置說明,下面的程序將不同通過編譯,編譯器將會給出類似缺少類型說明符這樣的出錯提示。

代碼一:

// ForwardDeclaration.h

#include <iostream>
using namespace std;

class B;             // 這是前置聲明(Forward declaration)
class A { private: B* b; public: A(B* b):b(b) { } … }; class B { … };

// Main.cpp

#include "ForwardDeclaration.h"

int main(int argc, char** argv)
{
         B* b = new B();
         A* a = new A(b);

         delete a;
         delete b;

         return 0;
}

上面程序可以順利編譯和運行(幾乎沒有做什么,也沒有輸出)

 

是不是有了前置說明就萬事大吉了呢?我們看看下面的代碼(帶陰影部分的代碼是新增加的)

代碼二:

// ForwardDeclaration.h

#include <iostream>
using namespace std;

class B;             // 這是前置聲明(Forward declaration)
class A
{
private:
         B* b;

public:
         A(B* b):b(b)
         {

         }

         void someMethod() { b->someMethod();                                                  // (1) }
};
 
class B
{
private:

public:
         void someMethod() { cout << "something happened..." << endl; }
};

// Main.cpp

#include "ForwardDeclaration.h"

int main(int argc, char** argv)
{
         B* b = new B();
         A* a = new A(b);
a
->someMethod(); delete a; delete b; return 0; }

一編譯,發現代碼(1)處出錯。出錯提示往往包括(不同的編譯器給出的提示會有所不同)

1.       使用了未定義的類型B

2.       “->somemethod”的左邊必須指向類/結構/聯合/泛型類型

 

原因:

1.       (1)處使用了類型B的定義,因為調用了類B中的一個成員函數。前置聲明class B;僅僅聲明了有一個B這樣的類型,而並沒有給出相關的定義,類B的相關定義,是在類A后面出現的,因此出現了編譯錯誤;

2.       代碼一之所以能夠通過編譯,是因為其中僅僅用到B這個類型,並沒有用到類B的定義。

 

解決辦法是什么?

將類的聲明和類的實現(即類的定義)分離。如下所示:

// ForwardDeclaration.h   類的聲明

#include <iostream>

using namespace std;

 
class B;             // 這是前置聲明(Forward declaration)

 
class A
{
private:

         B* b;

public:
         A(B* b);

         void someMethod();
};

 
class B

{

private:

public:

         void someMethod();

};

 

// ForwardDeclaration.cpp        類的實現

#include "ForwardDeclaration.h"

A::A(B* b):b(b)
{

}
 
void A::someMethod()
{
         b->someMethod();
}

void B::someMethod()
{
         cout << "something happened..." << endl;
}

// Main.cpp

#include "ForwardDeclaration.h"
int main(int argc, char** argv) { B* b = new B(); A* a = new A(b); a->someMethod(); delete a; delete b; return 0; }

結論:

前置聲明只能作為指針或引用,不能定義類的對象,自然也就不能調用對象中的方法了。

 

而且需要注意,如果將類A的成員變量B* b;改寫成B& b;的話,必須要將bA類的構造函數中,采用初始化列表的方式初始化,否則也會出錯。關於這點,詳見:特殊數據類型成員變量的初始化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM