一般情況下,C/C++要求所有的類型必須在使用前被定義,但是在一些特殊情況下,這種要求無法滿足,例如,在類time_outDialog中保留了對象指針,該對象用於顯示/修改一些信息。爲了實現對話框"應用"按鈕,把對話框做的修改立刻更新到time_outDialog界面上,爲此,需要在對話框類中需要保存 view類的指針,這樣定義關係就變成如下的代碼:
#define _TIME_OUTDIALOG_H_
#include <QDialog>
#include "../../mainwindow/mainwindow.h"
namespace Ui{
class time_outDialog;
}
class MainWindow;
class time_outDialog : public QDialog
{
Q_OBJECT
public:
time_outDialog(QWidget *parent = 0);
~time_outDialog();
private:
Ui::time_outDialog *ui;
MainWindow *mainwindow_ui;
private slots:
void on_OKButton_clicked();
void on_closeButton_clicked();
};
#define _MAINWINDOW_H_
#include "../Set/time_outDialog/time_outDialog.h"
#include <QtGui/QMainWindow>
#include <QLabel>
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
超前引用導致的錯誤有以下幾種處理辦法:
1) 使用類聲明
在超前引用一個類之前,首先用一個特殊的語句說明該標識符是一個類名,即將被超前引用。其使用方法是:
a) 用class ClassB;聲明即將超前引用的類名
b) 定義class ClassA
c) 定義class ClassB;
d) 編制兩個類的實現代碼。
上述方法適用於所有代碼在同一個文件中,一般情況下,ClassA和ClassB分別有自己的頭文件和cpp文件,這種
方法需要演變成:
a) 分別定義ClassA和ClassB,並在cpp文件中實現之
b) 在兩個頭文件的開頭分別用class ClassB;和class ClassA;聲明對方
c) 在兩個cpp文件中分別包含另外一個類的頭文件
NOTE:這種方法切記不可使用類名來定義變量和函數的變量參數,只可用來定義引用或者指針。
2) 使用全局變量
由於全局變量可以避免超前引用,不用贅述。我的習慣是,把類對象的extern語句加在該類頭文件的最後,大家喜歡
怎樣寫那都沒有什麼大問題,關鍵是保證不要在頭文件中胡亂包含。
3) 使用基類指針。
這種方法是在引用超前引用類的地方一律用基類指針。而一般情況下,兩個互相引用的類並不涉及其基類,因此不會造成
超前引用。以開始的例子說:在CMyDialog類中用CView*代替CMyView*,在CMyView類中用CDialog*代替CMyDialog*,這樣必然
不會造成超前引用。
說明:本文中,爲了敘述方便,把class AClass;語句成爲類AClass的聲明,把class AClass開始的對AClass的類成員變量、
成員函數原型等的說明稱爲類的定義,而把在CPP中的部分稱爲類的定義。如果大家對這三個詞有不同的理解,請按照自己的本意
把這三個詞換成相應的詞來理解。
一、類嵌套的疑問
C++頭文件重複包含實在是一個令人頭痛的問題,前一段時間在做一個簡單的數據結構演示程序的時候,不只一次的遇到這種問題。假設我們有兩個類A和B,分別定義在各自的有文件A.h和B.h中,但是在A中要用到B,B中也要用到A,但是這樣的寫法當然是錯誤的:
class A
class B 二、不同頭文件中的類的嵌套 在實際編程中,不同的類一般是放在不同的相互獨立的頭文件中的,這樣兩個類在相互引用時又會有不一樣的問題。重複編譯是問題出現的根本原因。爲了保證頭文 件僅被編譯一次,在C++中常用的辦法是使用條件編譯命令。在頭文件中我們常常會看到以下語句段(以VC++6.0自動生成的頭文件爲例):
#if !defined(AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDED_)
其中首句#if !defined也經常做#ifndef,作用相同。意思是如果沒有定義過這個宏,那麼就定義它,然後執行直到#endif的所有語句。如果下次在與要這 段代碼,由於已經定義了那個宏,因此重複的代碼不會被再次執行。這實在是一個巧妙而高效的辦法。在高版本的VC++上,還可以使用這個命令來代替以上的所 有: 但是不要以爲使用了這種機制就全部搞定了,比如在以下的代碼中:
//文件A.h中的代碼 #include "B.h"
class A
//文件B.h中的代碼 #include "A.h"
class B
這裏兩者都使用了指針成員,因此嵌套本身不會有什麼問題,在主函數前面使用#include "A.h"之後,主要編譯錯誤如下:
//文件A.h中的代碼 #include "B.h" class B;
class A
//文件B.h中的代碼 #include "A.h" class B;
class B 這樣至少可以說明,頭文件包含代替不了前置聲明。有的時候只能依靠前置聲明來解決問題。我們還要思考一下,有了前置聲明的時候頭文件包含還是必要的 嗎?我們嘗試去掉A.h和B.h中的#include行,發現沒有出現新的錯誤。那麼究竟什麼時候需要前置聲明,什麼時候需要頭文件包含呢? 三、兩點原則 頭文件包含其實是一想很煩瑣的工作,不但我們看着累,編譯器編譯的時候也很累,再加上頭文件中常常出現的宏定義。感覺各種宏定義的展開是非常耗時間的,遠不如自定義函數來得速度。我僅就不同頭文件、源文件間的句則結構問題提出兩點原則,僅供參考:
|