在涉及到友元类方法的时候会用到向前声明,至于为什么要使用向前声明我还是直接上例子理解的快:
在Tv类中Remote类中的set_chan()方法设为友元类方法,也就是Remote的这个方法是可以访问Tv的私有成员数据的(包括修改)。

1
2
3
4
5
class Tv
{
friend void Remote::set_chan(Tv & t, int c);
...
}

可以看到,既然是Tv类的友元,set_chan中自然要有Tv类的变量,但是编译器在编译Remote类的时候至少要知道Tv这个东西是个自定义的类,不然会报错,所以应该把Tv类声明在Remote类的前面。但是Tv类中由于将Remote中的方法设为自己的友元,所以编译器也要知道Remote::set_chan(Tv & t, int c)中的Remote以及它的方法是在哪里,不然也会报错。这样就前后矛盾了。

所以向前声明就是在这时候出现的。因为在Remote类中只是在参数中提到了Tv类,并没有提及Tv类的方法,因此只要要编译器知道Tv这是个什么东西就好了,所以向前声明一下,让编译器知道Tv是个类。因此类定义排序如下

1
2
3
4
5
6
7
class TV; // 向前声明
class Remote // Remote中提到了Tv一下,只要看到向前声明就可以了
{ ... };
class Tv // Tv也知道Remote的所有东西了
{ ... };

注意:这里需要注意的是Remote类定义中不能将类方法的定义直接写在类定义中了,因为在编译Remote的时候编译器还不知道Tv类里面有啥东西。所以应该将Remote的类方法定义写在其他地方,或者当前文件中使用inline关键字使其成为内联函数。


另外关于向前声明的作用我在google的C++编码规范中看到

使用前置声明尽量减少.h文件中的#include的数量

当一个头文件被包含的同时也引入了一项新的依赖(dependency),只要该头文件被修改,代码就要重新编译。如果你的头文件包含了其他头文件,这些头文件的任何改变也将导致那些包含了你的头文件的代码重新编译。因此,我们宁可尽量少包含头文件,尤其是那些包含在其他头文件中的

例如我头文件中用到了File类但是我并不需要访问File的声明(也就是知道他是个什么东西就行的程度),则只需前置声明class File;无需

1
#include "file/base/file.h"

那具体哪些情况下只是用类而不需要访问File类定义呢?

  1. 将参数成员类型声明为File *File &
  2. 参数、返回值类型为File的函数只是声明(但不定义实现)
  3. 静态数据成员的类型可以被声明为File,因为静态数据成员的定义在类定义之外。
如果类是File类的子类或者还有类型为File的非静态数据成员,则必须包含有其定义的头文件。

Comments

2016-03-14