#include和前置声明(forward declaration)
1. 当不需要调用类的实现时,包括constructor,copy constructor,assignment operator,member function,甚至是address-of operator时,就不用#include,只要forward declaration就可以了。
2. 当要用到类的上面那些“方法”时,就要#include
例子:
boy.h
#ifndef __BOY__H_
#define __BOY__H_
#include<string>
using namespace std;
class Boy {
private:
string name;
int age;
};
#endif
test1.h
#include<iostream>
class Boy;
class People {
Boy getBoyInfo();
};
test2.h
#include<iostream>
#include "boy.h"
class Boy;
class People {
Boy getBoyInfo();
};
一个采用前置声明,一个采用#include "boy.h"加入了Boy的定义。两种方法都能通过编译。但是test1.h 这种写法更好。如果boy.h 的private成员变量改变,比如变成 char *name; test1.h 不需要重新编译,而test2.h 就要重新编译,更糟的是如果test2.h 还与其他很多头文件有依赖关系,就会引发一连串的重新编译,花费极大的时间。可是事实上改变一下写法就可以省去很多功夫。所以能用前置声明代替#include 的时候,尽量用前置声明
有些情况不能用前置声明代替#include
比如test1.h改成
#include<iostream>
using namespace std;
class Boy;
class People {
public:
Boy boy;
};
test.cpp:7:9: error: field ‘boy’ has incomplete type
Boy boy;
^
会编译错误,因为Boy boy定义了一个Boy类型变量,编译器为boy分配内存空间的时候必须知道boy的大小,必须包含定义Boy类的boy.h文件。
这是可以采用指针来代替
#include<iostream>
using namespace std;
class Boy;
class People {
public:
Boy *boy;
};
指针的大小是固定的。在32位机上是4字节,64位机上是8字节。这时编译Task1的时候不需要Boy的大小,所以和Boy的定义无关。
如果使用object reference 或 object point 可以完成任务,就不要用object
这样可以尽最大可能避免#include
为声明式和定义是提供不同的头文件
第一个原则应该是,如果可以不包含头文件,那就不要包含了。这时候前置声明可以解决问题。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象(非指针),也没有访问到类的具体成员,那么前置声明就可以了。因为指针这一数据类型的大小是特定的,编译器可以获知。
第二个原则应该是,尽量在CPP文件中包含头文件,而非在头文件中。假设类A的一个成员是是一个指向类B的指针,在类A的头文件中使用了类B的前置声明并编译成功,那么在A的实现中我们需要访问B的具体成员,因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类B的头文件而非在声明部分(H文件)包含。