程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 淺析C++中前置聲明的運用與圈套

淺析C++中前置聲明的運用與圈套

編輯:關於C++

淺析C++中前置聲明的運用與圈套。本站提示廣大學習愛好者:(淺析C++中前置聲明的運用與圈套)文章只能為提供參考,不一定能成為您想要的結果。以下是淺析C++中前置聲明的運用與圈套正文


前置聲明的應用
有必定C++開辟經歷的同伙能夠會碰到如許的場景:兩個類A與B是強耦合關系,類A要援用B的對象,類B也要援用類A的對象。好的,不難,我的第一向覺讓我寫出如許的代碼:

// A.h
#include "B.h"
class A
{

public:
    A(void);
    virtual ~A(void);
};
//A.cpp
#include "A.h"
A::A(void)
{
}
A::~A(void)
{
}
// B.h
#include "A.h"
class B
{
    A a;
public:
    B(void);
    ~B(void);
};
// B.cpp
#include "B.h"
B::B(void)
{
}
B::~B(void)
{
}

好的,完成,編譯一下A.cpp,欠亨過。再編譯B.cpp,照樣欠亨過。編譯器都被弄暈了,編譯器去編譯A.h,發明包括了B.h,就去編譯B.h。編譯B.h的時刻發明包括了A.h,然則A.h曾經編譯過了(其實沒有編譯完成,能夠編譯器做了記載,A.h曾經被編譯了,如許可以免墮入逝世輪回。編譯失足總比逝世輪回強點),就沒有再次編譯A.h就持續編譯。前面發明用到了A的界說,這下好了,A的界說並沒有編譯完成,所以找不到A的界說,就編譯失足了。提醒信息以下:
1>d:/vs2010/test/test/a.h(5): error C2146: syntax error : missing ';' before identifier 'b'
1>d:/vs2010/test/test/a.h(5): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>d:/vs2010/test/test/a.h(5): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
那怎樣辦?有方法,C++為我們供給了前置聲明。前置聲明是甚麼?舉個抽象點的例子,就是我要蓋一個房子(CHOuse),光有房子還不可啊,我還得有床(CBed)。然則房子還沒蓋好,總不克不及先買床吧,床的年夜小我定了,改天買。先得把房子蓋好,蓋房子的時刻我先給床留個地位,等房子蓋好了,我再決議買甚麼樣的床。前置聲明就是我在聲明一個類(CHouse)的時刻,用到了別的一個類的界說(CBed),然則CBed還沒有界說呢,並且我還先不須要CBed的界說,只需曉得CBed是一個類就夠了。那好,我就先聲明類CBed,告知編譯器CBed是一個類(不消包括CBed的頭文件):

class CBed;

然後在CHouse頂用到CBed的,都用CBed的指針類型代(由於指針類型固定年夜小的,然則CBed的年夜小只用曉得了CBed界說能力肯定)。比及要完成CHouse界說的時刻,就必需要曉得CBed的界說了,那是再包好CBed的頭文件就好了。

前置聲明有時刻很有效,好比說兩個類互相依附的時刻要。還有前置聲明可以削減頭文件的包括條理,削減失足能夠。下面說的例子。

// House.h
class CBed; // 蓋房子時:如今先不買,確定要買床的
class CHouse
{
    CBed* bed; // 我先給床留個地位
public:
    CHouse(void);
    virtual ~CHouse(void);
    void GoToBed();
};
// House.cpp
#include "Bed.h"
#include "House.h" // 等房子開端裝修了,要買床了
CHouse::CHouse(void)
{
    bed = new CBed(); // 把床放進房子
}
CHouse::~CHouse(void)
{
}
void CHouse::GoToBed()
{
    bed->Sleep();
}
// Bed.h
class CBed
{
public:
    CBed(void);
    ~CBed(void);
    void Sleep();
};
// Bed.cpp
#include "Bed.h"
CBed::CBed(void)
{
}
CBed::~CBed(void)
{
}
void CBed::Sleep()
{
}

前置聲明中的圈套
留意這裡有圈套:
1、CBed* bed;必需用指針或援用
援用版本:

// House.h
class CBed; // 蓋房子時:如今先不買,確定要買床的
class CHouse
{
    CBed& bed; // 我先給床留個地位
    // CBed bed; // 編譯失足
public:
    CHouse(void);
    CHouse(CBed& bedTmp);
    virtual ~CHouse(void);
    void GoToBed();
};
// House.cpp
#include "Bed.h"
#include "House.h" // 等房子開端裝修了,要買床了
CHouse::CHouse(void)
    : bed(*new CBed())
{
    CBed* bedTmp = new CBed(); // 把床放進房子
    bed = *bedTmp;
}
CHouse::CHouse(CBed& bedTmp)
    : bed(bedTmp)
{
}
CHouse::~CHouse(void)
{
    delete &bed;
}
void CHouse::GoToBed()
{
    bed.Sleep();
}

2、不克不及在CHouse的聲明中應用CBed的辦法
應用了不決義的類型CBed;
bed->Sleep的右邊必需指向類/構造/結合/泛型類型

class CBed; // 蓋房子時:如今先不買,確定要買床的
class CHouse
{
    CBed* bed; // 我先給床留個地位
    // CBed bed; // 編譯失足
public:
    CHouse(void);
    virtual ~CHouse(void);
    void GoToBed()
    {
        bed->Sleep();  // 編譯失足,床都沒買,怎樣能睡
    }
};

3、在CBed界說之前挪用CBed的析構函數

// House.h
class CBed; // 蓋房子時:如今先不買,確定要買床的
class CHouse
{
    CBed* bed; // 我先給床留個地位
    // CBed bed; // 編譯失足
public:
    CHouse(void);
    virtual ~CHouse(void);
    void GoToBed();
    void RemoveBed()
    {
        delete bed; // 我不須要床了,我要把床拆失落。還沒買怎樣拆?
    }
};
// House.cpp
#include "Bed.h"
#include "House.h" // 等房子開端裝修了,要買床了
CHouse::CHouse(void)
{
    bed = new CBed(); // 把床放進房子
}
CHouse::~CHouse(void)
{
    int i = 1;
}
void CHouse::GoToBed()
{
    bed->Sleep();
}
// Bed.h
class CBed
{
    int* num;
public:
    CBed(void);
    ~CBed(void);
    void Sleep();
};
// Bed.cpp
#include "Bed.h"
CBed::CBed(void)
{
    num = new int(1);
}
CBed::~CBed(void)
{
    delete num; // 挪用不到
}
void CBed::Sleep()
{
}
//main.cpp
#include "House.h"
int main()
{
    CHouse house;
    house.RemoveBed();
}

前置聲明處理兩個類的相互依附
接上去,給出開篇第一個成績的謎底:

// A.h
class B;
class A
{
    B* b;
public:
    A(void);
    virtual ~A(void);
};
//A.cpp
#include "B.h"
#include "A.h"
A::A(void)
{
    b = new B;
}
A::~A(void)
{
}
// B.h
class A;
class B
{
    A a;
public:
    B(void);
    ~B(void);
};
// B.cpp
#include "A.h"
#include "B.h"
B::B(void)
{
    a = New A;
}
B::~B(void)
{
}

前置聲明在友元類辦法中的運用
《C++ Primer 4Edition》在類的友元一章節中說到,假如在一個類A的聲明中將另外一個類B的成員函數聲明為友元函數F,那末類A必需事前曉得類B的界說;類B的成員函數F聲明假如應用類A作為形參,那末也必需曉得類A的界說,那末兩個類就相互依附了。要處理這個成績必需應用類的前置聲明。例如:

// House.h
#include "Bed.h"
class CHouse
{
    friend void CBed::Sleep(CHouse&);
public:
    CHouse(void);
    virtual ~CHouse(void);
    void GoToBed();
    void RemoveBed()
    {
    }
};
// House.cpp
#include "House.h"
CHouse::CHouse(void)
{
}
CHouse::~CHouse(void)
{
    int i = 1;
}
void CHouse::GoToBed()
{
}
// Bed.h
class CHouse;
class CBed
{
    int* num;
public:
    CBed(void);
    ~CBed(void);
    void Sleep(CHouse&);
};
// Bed.cpp
#include "House.h"
CBed::CBed(void)
{
    num = new int(1);
}
CBed::~CBed(void)
{
    delete num;
}
void CBed::Sleep(CHouse& h)
{
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved