源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

浅析C++中前置声明的应用与陷阱

  • 时间:2020-08-13 21:47 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:浅析C++中前置声明的应用与陷阱
[b]前置声明的使用 [/b]有一定C++开发经验的朋友可能会遇到这样的场景:两个类A与B是强耦合关系,类A要引用B的对象,类B也要引用类A的对象。好的,不难,我的第一直觉让我写出这样的代码:
[u]复制代码[/u] 代码如下:
// 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 [b]那怎么办?[/b]有办法,C++为我们提供了前置声明。前置声明是什么?举个形象点的例子,就是我要盖一个屋子(CHOuse),光有屋子还不行啊,我还得有床(CBed)。但是屋子还没盖好,总不能先买床吧,床的大小我定了,改天买。先得把房子盖好,盖房子的时候我先给床留个位置,等房子盖好了,我再决定买什么样的床。前置声明就是我在声明一个类(CHouse)的时候,用到了另外一个类的定义(CBed),但是CBed还没有定义呢,而且我还先不需要CBed的定义,只要知道CBed是一个类就够了。那好,我就先声明类CBed,告诉编译器CBed是一个类(不用包含CBed的头文件):
[u]复制代码[/u] 代码如下:
class CBed;
然后在CHouse中用到CBed的,都用CBed的指针类型代(因为指针类型固定大小的,但是CBed的大小只用知道了CBed定义才能确定)。等到要实现CHouse定义的时候,就必须要知道CBed的定义了,那是再包好CBed的头文件就行了。 前置声明有时候很有用,比如说两个类相互依赖的时候要。还有前置声明可以减少头文件的包含层次,减少出错可能。[b]上面说的例子。 [/b]
[u]复制代码[/u] 代码如下:
// 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() { }
[b]前置声明中的陷阱 [/b]注意这里有陷阱: [b]1、CBed* bed;必须用指针或引用 [/b]引用版本:
[u]复制代码[/u] 代码如下:
// 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(); }
[b]2、不能在CHouse的声明中使用CBed的方法 [/b]使用了未定义的类型CBed; bed->Sleep的左边必须指向类/结构/联合/泛型类型
[u]复制代码[/u] 代码如下:
class CBed; // 盖房子时:现在先不买,肯定要买床的 class CHouse {     CBed* bed; // 我先给床留个位置     // CBed bed; // 编译出错 public:     CHouse(void);     virtual ~CHouse(void);     void GoToBed()     {         bed->Sleep();  // 编译出错,床都没买,怎么能睡     } };
[b]3、在CBed定义之前调用CBed的析构函数 [/b]
[u]复制代码[/u] 代码如下:
// 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(); }
[b]前置声明解决两个类的互相依赖 [/b]接下来,给出开篇第一个问题的答案:
[u]复制代码[/u] 代码如下:
// 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) { }
[b]前置声明在友元类方法中的应用 [/b]《C++ Primer 4Edition》在类的友元一章节中说到,如果在一个类A的声明中将另一个类B的成员函数声明为友元函数F,那么类A必须事先知道类B的定义;类B的成员函数F声明如果使用类A作为形参,那么也必须知道类A的定义,那么两个类就互相依赖了。要解决这个问题必须使用类的前置声明。例如:
[u]复制代码[/u] 代码如下:
// 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) { }
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部