前向声明
文章目录
定义
有些时候我们可以声明一些类但是并不去定义它,当然这个类的作用也很有限了。
比如class foo;
声明一个foo类,这个声明,有时候也叫做前向声明(forward declaration),在声明完这个foo类之后,定义完这个foo类之前的时期,foo类是一个不完全的类型(incomplete type),也就是说foo类是一个类型,但是这个类型的一些性质(比如包含哪些成员,具有哪些操作)都不知道。
作用
这个类的作用很有限.
- 不能定义foo类的对象。
- 可以用于定义指向这个类型的指针或引用。
- 用于声明(不是定义)使用该类型作为形参或者返回类型的函数。
应用
在c++中,如果要为类编写头文件的话,一般是要#include一堆头文件的,但利用前向声明和c++编译器的特性,其中大部分是不需要的。
c++编译器做的事情主要是:
-
扫描符号;
-
确定对象大小。
所以很多时候并不需要将类都include进来。
-
由于所有对象类型的引用所占用的空间都是相同大的,所以c++编译器很好确认对象大小。
1 2 3 4 5 6
class string; class Sample { private: string &s; };
``
这里只需要做一个string的前向声明就可以了,不需要#include
-
由于所有类型的指针也是相同大小的。也可以只做前向声明就好。
1 2 3 4 5 6
class string; class Sample { private: string *s; };
``
这里只需要做一个string的前向声明就可以了,不需要#include
-
声明成员函数的形参或者是返回类型,也可以利用前向声明的性质。
1 2 3 4 5 6 7 8 9 10
class string; class foo; class Sample { public: foo foo_test(foo &); private: string &s; foo *f; };
``
这里,我根本没有定义一个foo类,但是还是可以这样用,因为成员函数不占类对象的大小,所以c++编译器还是可以确定对象的大小。
前向声明的作用在于告诉编译器这个一个在别的地方定义的类型。这样C++编译器就能生成正确的符号表了。
解决两个类互相包含引用的问题
在构造自己的类时,有可能会碰到两个类之间的相互引用问题,例如:定义了类A类B,A中使用了B定义的类型,B中也使用了A定义的类型
class A
{
int i;
B b;
}
class B
{
int i;
A* a;
}
一般来说,两者的定义,至少有一方是使用指针,或两者都使用指针,但是决不能两者都定义实体对象。
class A
{
int i;
B b;
}
class B
{
int i;
A a;
}
言归正传,那么,在定义时因为相互引用肯定会需要相互包含头文档,假如仅仅只是在各自的头文档中包含对方的头文档,是通但是编译的,如下:
//class A.h
#include "B.h"
class A
{
int i;
B b;
}
//class B.h
#include "A.h"
class B
{
int i;
A *a;
}
如上的包含方式可能会造成编译器有错误提示:A.h文档中使用了未知类型B。怎么办?
一般的做法是:两个类的头文档之中,选一个包含另一个类的头文档,但另一个头文档中只能采用class*;的声明形式,而在实现文档中(*.cpp)中包含头文档,如下:
//class A.h
#include "B.h"
class A
{
int i;
B b;
}
//class B.h
class A;
class B
{
int i;
A *a;
}
//B.cpp
//在B.cpp中的文档包含处要有下面语句,否则不能调用成员a的任何内容
#include "A.h"
B::B()
{
……
}
文章作者 Forz
上次更新 2017-06-23