小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

QT4(C++)兩個(gè)頭文件相互包含(類超前引用)

 知識的海洋625 2014-04-23
1、C++中的類相互包含(QT4)
     所謂超前引用是指一個(gè)類型在定義之前就被用來定義變量和聲明函數(shù)。
    一般情況下,C/C++要求所有的類型必須在使用前被定義,但是在一些特殊情況下,這種要求無法滿足,例如,在類time_outDialog中保留了對象指針,該對象用于顯示/修改一些信息。為了實(shí)現(xiàn)對話框"應(yīng)用"按鈕,把對話框做的修改立刻更新到time_outDialog界面上,為此,需要在對話框類中需要保存 view類的指針,這樣定義關(guān)系就變成如下的代碼:

time_outDialog.h中的代碼:

#ifndef _TIME_OUTDIALOG_H_
#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();
};

#endif  // end of the time_outDialog.h


mainwindow.h文件中的代碼:

#ifndef _MAINWINDOW_H_
#define _MAINWINDOW_H_

#include "../Set/time_outDialog/time_outDialog.h"

#include <QtGui/QMainWindow>
#include <QLabel>


namespace Ui
{
        class MainWindow;
}

class time_outDialog;

class MainWindow : public QMainWindow
{
        Q_OBJECT
public:
…………
};

#endif  // The end of _MAINWINDOW_H_

   更一般的情況,類A和類B需要彼此互相引用,這樣必然有一個(gè)類會(huì)先被定義,而另外一個(gè)類后被定義,這樣在先被定義的類引用后被定義的類的時(shí)候,就導(dǎo)致了所謂的超前引用。

   超前引用導(dǎo)致的錯(cuò)誤有以下幾種處理辦法:
   1) 使用類聲明
   在超前引用一個(gè)類之前,首先用一個(gè)特殊的語句說明該標(biāo)識符是一個(gè)類名,即將被超前引用。其使用方法是:
           a)  用class ClassB;聲明即將超前引用的類名
           b)  定義class ClassA
           c)  定義class ClassB;
           d)  編制兩個(gè)類的實(shí)現(xiàn)代碼。
    上述方法適用于所有代碼在同一個(gè)文件中,一般情況下,ClassA和ClassB分別有自己的頭文件和cpp文件,這種
方法需要演變成:
           a) 分別定義ClassA和ClassB,并在cpp文件中實(shí)現(xiàn)之
           b) 在兩個(gè)頭文件的開頭分別用class ClassB;和class ClassA;聲明對方
           c) 在兩個(gè)cpp文件中分別包含另外一個(gè)類的頭文件
    NOTE:這種方法切記不可使用類名來定義變量和函數(shù)的變量參數(shù),只可用來定義引用或者指針。    
    2) 使用全局變量
    由于全局變量可以避免超前引用,不用贅述。我的習(xí)慣是,把類對象的extern語句加在該類頭文件的最后,大家喜歡
怎樣寫那都沒有什么大問題,關(guān)鍵是保證不要在頭文件中胡亂包含。
    3) 使用基類指針。
    這種方法是在引用超前引用類的地方一律用基類指針。而一般情況下,兩個(gè)互相引用的類并不涉及其基類,因此不會(huì)造成
超前引用。以開始的例子說:在CMyDialog類中用CView*代替CMyView*,在CMyView類中用CDialog*代替CMyDialog*,這樣必然
不會(huì)造成超前引用。

    說明:本文中,為了敘述方便,把class AClass;語句成為類AClass的聲明,把class AClass開始的對AClass的類成員變量、
成員函數(shù)原型等的說明稱為類的定義,而把在CPP中的部分稱為類的定義。如果大家對這三個(gè)詞有不同的理解,請按照自己的本意
把這三個(gè)詞換成相應(yīng)的詞來理解。


C++中頭文件相互包含的幾點(diǎn)問題
2007-06-19 17:42

一、類嵌套的疑問

C++頭文件重復(fù)包含實(shí)在是一個(gè)令人頭痛的問題,前一段時(shí)間在做一個(gè)簡單的數(shù)據(jù)結(jié)構(gòu)演示程序的時(shí)候,不只一次的遇到這種問題。假設(shè)我們有兩個(gè)類A和B,分別定義在各自的有文件A.h和B.h中,但是在A中要用到B,B中也要用到A,但是這樣的寫法當(dāng)然是錯(cuò)誤的:
class B;

class A
{
      public:
          B b;
};

class B
{
      public:
          A a;
};
因?yàn)樵贏對象中要開辟一塊屬于B的空間,而B中又有A的空間,是一個(gè)邏輯錯(cuò)誤,無法實(shí)現(xiàn)的。在這里我們只需要把其中的一個(gè)A類中的B類型成員改成指針形式 就可以避免這個(gè)無限延伸的怪圈了。為什么要更改A而不是B?因?yàn)榫退隳阍贐中做了類似的動(dòng)作,也仍然會(huì)編譯錯(cuò)誤,表面上這僅僅上一個(gè)先后順序的問題。
      為什么會(huì)這樣呢?因?yàn)镃++編譯器自上而下編譯源文件的時(shí)候,對每一個(gè)數(shù)據(jù)的定義,總是需要知道定義的數(shù)據(jù)的類型的大小。在預(yù)先聲明語句class B;之后,編譯器已經(jīng)知道B是一個(gè)類,但是其中的數(shù)據(jù)卻是未知的,因此B類型的大小也不知道。這樣就造成了編譯失敗,VC++6.0下會(huì)得到如下編譯錯(cuò) 誤:
      error C2079: 'b' uses undefined class 'B'
將A中的b更改為B指針類型之后,由于在特定的平臺上,指針?biāo)嫉目臻g是一定的(在Win32平臺上是4字節(jié)),這樣可以通過編譯。

二、不同頭文件中的類的嵌套

      在實(shí)際編程中,不同的類一般是放在不同的相互獨(dú)立的頭文件中的,這樣兩個(gè)類在相互引用時(shí)又會(huì)有不一樣的問題。重復(fù)編譯是問題出現(xiàn)的根本原因。為了保證頭文 件僅被編譯一次,在C++中常用的辦法是使用條件編譯命令。在頭文件中我們常常會(huì)看到以下語句段(以VC++6.0自動(dòng)生成的頭文件為例):

#if !defined(AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDED_)
#define AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDED_
      //很多語句……
#endif

其中首句#if !defined也經(jīng)常做#ifndef,作用相同。意思是如果沒有定義過這個(gè)宏,那么就定義它,然后執(zhí)行直到#endif的所有語句。如果下次在與要這 段代碼,由于已經(jīng)定義了那個(gè)宏,因此重復(fù)的代碼不會(huì)被再次執(zhí)行。這實(shí)在是一個(gè)巧妙而高效的辦法。在高版本的VC++上,還可以使用這個(gè)命令來代替以上的所 有:
      #pragma once
它的意思是,本文件內(nèi)的代碼只被使用一次。

      但是不要以為使用了這種機(jī)制就全部搞定了,比如在以下的代碼中:

//文件A.h中的代碼
#pragma once

#include "B.h"

class A
{
      public:
          B* b;
};

//文件B.h中的代碼
#pragma once

#include "A.h"

class B
{
      public:
          A* a;
};

這里兩者都使用了指針成員,因此嵌套本身不會(huì)有什么問題,在主函數(shù)前面使用#include "A.h"之后,主要編譯錯(cuò)誤如下:
      error C2501: 'A' : missing storage-class or type specifiers
仍然是類型不能找到的錯(cuò)誤。其實(shí)這里仍然需要前置聲明。分別添加前置聲明之后,可以成功編譯了。代碼形式如下:

//文件A.h中的代碼
#pragma once

#include "B.h"

class B;

class A
{
      public:
          B* b;
};

//文件B.h中的代碼
#pragma once

#include "A.h"

class B;

class B
{
      public:
          A* a;
};

這樣至少可以說明,頭文件包含代替不了前置聲明。有的時(shí)候只能依靠前置聲明來解決問題。我們還要思考一下,有了前置聲明的時(shí)候頭文件包含還是必要的 嗎?我們嘗試去掉A.h和B.h中的#include行,發(fā)現(xiàn)沒有出現(xiàn)新的錯(cuò)誤。那么究竟什么時(shí)候需要前置聲明,什么時(shí)候需要頭文件包含呢?

三、兩點(diǎn)原則

      頭文件包含其實(shí)是一想很煩瑣的工作,不但我們看著累,編譯器編譯的時(shí)候也很累,再加上頭文件中常常出現(xiàn)的宏定義。感覺各種宏定義的展開是非常耗時(shí)間的,遠(yuǎn)不如自定義函數(shù)來得速度。我僅就不同頭文件、源文件間的句則結(jié)構(gòu)問題提出兩點(diǎn)原則,僅供參考:


第一個(gè)原則應(yīng)該是,如果可以不包含頭文件,那就不要包含了。這時(shí)候前置聲明可以解決問題。如果使用的僅僅是一個(gè)類的指針,沒有使用這個(gè)類的具體對象(非指針),也沒有訪問到類的具體成員,那么前置聲明就可以了。因?yàn)橹羔樳@一數(shù)據(jù)類型的大小是特定的,編譯器可以獲知。


第二個(gè)原則應(yīng)該是,盡量在CPP文件中包含頭文件,而非在頭文件中。假設(shè)類A的一個(gè)成員是是一個(gè)指向類B的指針,在類A的頭文件中使用了類B的前置聲明并 便宜成功,那么在A的實(shí)現(xiàn)中我們需要訪問B的具體成員,因此需要包含頭文件,那么我們應(yīng)該在類A的實(shí)現(xiàn)部分(CPP文件)包含類B的頭文件而非聲明部分 (H文件)。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多