前向声明(Forward declaration)

来源:互联网 发布:mysql设置默认值 编辑:程序博客网 时间:2024/04/28 13:20

在使用pcre库时,在pcre.h的头文件中有如下两行代码1.struct real_pcre;                 /* declaration; the definition is private  */2.typedef struct real_pcre pcre;

这里声明了struct real_pcre,但并未对其定义,而pcre库中使用了该类型。

这是前向声明(Forward declaration)的使用,前向声明可使用在当某处要使用某种类型,而并不打算此时就定义这种类型或者可能还未明确该类型的具体成员,可先进行声明,以便进行引用。


对于前面声明的用途,有篇文章分析的比较好,该文章转载如下:

【原文链接】http://www.cnblogs.com/baochun968/archive/2012/05/03/2480137.html

下面主要介绍了前向声明概念、用法以及和#include区别

前向声明概念(forward declaration)

在程序中引入了类类型的B.在声明之后,定义之前,类B是一个不完全类型(incompete type),即已知B是一个类型,但不知道包含哪些成员.不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数.

前向声明应用场景

当你需要定义两个类或者结构,例如A和B,而这两个类需要互相引用,这时候在定义A的时候,B还没有定义,那怎么引用它呢,这时候就需要前向声明(forward declaration)了,前向声明格式如下: class B;当你在定义类A之前声明了B,那么就会在程序中引入了类类型的B,编译器知道你会在后面的某个地方定义类B,所以允许你在类A中引用类B。但是,在声明之后,定义之前,类B是一个不完全类型(incompete type),即已知B是一个类型,但不知道这个类型的一些性质(比如包含哪些成员和操作)。

前向声明的使用限制:(就拿上面声明B类说明)

1.不恩能够定义B类的对象;

2.可以用于定义只想这个类型的指针或者引用;

3.用于声明使用该类型作为形参或者返回类型的函数;

除了上面的限制,我们可以用它做些什么事情吗?

在C++中,如果要编写一个新类的头文件,一般是要#include一堆依赖的头文件,但利用前向声明和c++编译器的特性,可以减少这里的工作量。

因为c++编译器做的事情主要是:1.扫描符号;2.确定对象大小。利用这个特性,当我们编写一个新类的头文件时,就可以用前向声明,减少大量的#include,减少编译的

工作量。

例如:

1.B类用到A类,操作如下,就不需要加A.h了,减少编译工作量

 1:     2: //B.h   3: class A;//调用类A,前向声明   4: class    5: B   6: {   7: private:   8: A *a; //声明指针   9: };

2.在声明成员函数的形参或者返回类型时,也可以用前向声明

即使我们没有定义一个foo类,也可以用,因为成员函数不占类对象的大小,编译器可以确定对象大小,前向声明的作用在于告诉编译器这个一个在别的地方定义的类型。这样编译器就能生成正确的符号表了。

  1:     2: //Sample.h   3: class foo;   4: class    5: Sample   6: {   7: private:   8: foo foo_test(foo &);   9: };

常犯错误:
 1:     2: #ifndef RESOURCE_H   3: #define RESOURCE_H   4: class    5: mybitmap;   6: class    7: resource   8: {   9: public:  10: resource();  11: ~resource();  12: private:  13: mybitmap*   14: m_pBitmap;  15: };  16: #endif  17: resource::~resource()  18: {  19: if (   20: NULL != m_pBitmap )  21: {  22: delete m_pBitmap;  23: }  24: }

程序编译时,会有一个警告,deletion of pointer to incomplete type 'mybitmap'; no destructor called(没有实践)

原因就在于#include和class的区别:class如上面所说,而#include是包括一个类的所有定义、成员和方法等信息。

class A 声明仅仅告诉程序有这样一个类,你可以在这里声明类A的一个指针,但是此处并不能获得类A的具体信息,如果定义类A的一个指针是可以的,但定义一个类A的对象,则程序是错误的,因为不知道A的具体信息,故无法生成一个对象。原因是程序中用class声明的mybitmap类,在执行delete m_pBitmap时,因为它不知道mybitmap类的具体信息,所以无法调用它的析构函数,故内存并没有释放,造成内存泄漏。