浅分析C++中前置声明の応用と落とし穴

6533 ワード

前の文の使用は一定の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.cpをコンパイルしても通りません。コンパイラは、B.hを含むコンパイラA.hをコンパイルします。B.hをコンパイルします。B.hをコンパイルする時、A.hが含まれていますが、A.hはコンパイル済みです。(実はコンパイラが作成されていません。A.hはすでにコンパイルされています。このようにすれば、死のサイクルに陥るのを避けることができます。コンパイルエラーは常にデッドサイクルより強いです。後にAの定義が使われていることが分かりました。これでいいです。Aの定義はコンパイルされていませんので、Aの定義が見つかりません。コンパイルが間違っています。ヒントは以下の通りです。1>d:/vs 2010/test/test/a.h(5):error C 2146:sysntax error:missing';before identifer'b'1'd:/vs 2010/test/test/a.h(5):error C 4430:missing type specifer-int.Note:C++does not support default t t t t t t t t int t t t t t t t t t t 1>d:vs 2010/test/test/test/test/ath.mith(5)どうやって作りますか?方法があります。C++は前の声明を提供してくれました。前の宣言は何ですか?イメージポイントの例を挙げると、家を建てるだけではだめです。ベッドがあります。でも、部屋はまだ建てられていません。先にベッドを買うことはできないでしょう。ベッドの大きさはもう決めました。後で買います。まず家を建てなければなりません。家を建てる時はまずベッドの位置を残して、家が建てられたら、どのようなベッドを買うかを決めます。前の声明は私が一つの種類を声明する時、もう一つの種類の定義(CBed)を使いましたが、CBedはまだ定義されていません。はい、先声明類CBedについて、コンパイラCBedはクラス(CBedのヘッダファイルを含まない)です。

class CBed;
はその後CHOuseで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()
{
}
前置声明の中の落とし穴はここに落とし穴があります。ポインタまたは引用バージョンを使用しなければならない:

// 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();
}
を呼び出して、2つのクラスの相互依存性を解決しなければならない。続いて、冒頭の問題に対する答えを与える。

// 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 4 Edition」を適用する。あるクラス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)
{
}