C++中前置声明的应用与陷阱
来源:互联网 发布:网络融资平台有哪些 编辑:程序博客网 时间:2024/05/18 00:51
前置声明的使用
有一定C++开发经验的朋友可能会遇到这样的场景:两个类A与B是强耦合关系,类A要引用B的对象,类B也要引用类A的对象。好的,不难,我的第一直觉让我写出这样的代码:
- // A.h
- #include "B.h"
- class A
- {
- B b;
- 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)
- {
- }
转载:http://blog.csdn.net/yunyun1886358/article/details/5672574
- C++中前置声明的应用与陷阱
- C++中前置声明的应用与陷阱(转)
- C++中前置声明的应用与陷阱
- C++之前置声明的应用与陷阱详解
- 类前置声明的应用
- 对c语言陷阱与缺陷中函数声明理解
- Python的C扩展-应用与陷阱
- Python的C扩展-应用与陷阱
- C++中类的前置声明
- c++中类的前置声明
- C++中前置声明的使用
- typedef与前置声明
- 前置声明与#include
- #include与前置声明
- C++中前置声明
- 【C++学习与应用总结】2: 关于类型前置声明
- 前置声明的使用
- C++的前置声明
- JavaScript_两个练习
- uncaught exception: Highcharts error #13: www.highcharts.com/errors/13问题的解决方法
- sizeToFit
- android sdk location should not contain whitespace
- 设置具有超时功能的执行方法
- C++中前置声明的应用与陷阱
- iOS深入学习(使用CocoaPods进行第三方资源管理)(转)
- Linux 系统应用编程——标准I/O
- 解决SpringMvc中org.springframework.web.servlet.DispatcherServlet noHandlerFound的错误
- 2093: [Poi2010]Frog 倍增
- 数学之美——信息的度量
- 企业培训的多角度开发
- 欧拉角是什么
- Hadoop 与 Spark 和 HBase 常用配置参数总结