当我们有两个类的头文件互相包含时,如果出现一个类中有另一个类的对象时,VS就会报这样的错error C4430: 缺少类型说明符 - 假定为 int。
test2.h
#ifndef __test2_H__
#define __test2_H__
#include<iostream>
#include "test1.h"
using namespace std;
class test2
{
public:
int sub(int a,int b);
test1 a;
};
#endif // !1
test1.h
#ifndef __test1_H__
#define __test1_H__
#include<iostream>
#include "test2.h"
using namespace std;
class test1
{
public:
int add(int a,int b);
};
#endif // !__test1_H__
test2.cpp
#include "test2.h"
int sub(int a, int b)
{
return a - b;
}
test1.cpp
#include "test1.h"
int test1::add(int a, int b)
{
return a + b;
}
预处理指令
C\C++头文件在开始一般习惯使用#ifndef…..#define……#endif作为预处理标识符来防止头文件重复包含,如果不使用头文件就会一直递归包含下去,编译器在编译test2.h头文件时,遇到了#include "test1.h"
,就会打开test1.h进行编译,这相当于把test1.h的内容放到了#include "test1.h"
处,而在编译test1.h时,又会遇到#include "test2.h"
,编译器又会打开test2.h进行编译,这样就会一直递归包含下去,所以预编译指令很有用哒!
回到问题
回到最开始的问题,怎么解决它呢,问了别人才知道,在test1 a;
前面加上class test1;
的前置声明,为什么要加呢?
对于test1.cpp,test1.cpp包含了test1.h,那么就会展开test1.h,而test1.h又包含了test2.h,那么也展开它,那么现在test1.cpp中就相当于
class test2
{
public:
int sub(int a,int b);
test1 a;
};
class test1
{
public:
int add(int a,int b);
};
int test1::add(int a, int b)
{
return a + b;
}
此时问题就显而易见了,test1 a;
之前,根本就没有发现class test1
的类定义,所以要在test2.h中test1 a;
之前加前置声明。
test2.h
#ifndef __test2_H__
#define __test2_H__
#include<iostream>
#include "test1.h"
using namespace std;
class test1;
class test2
{
public:
int sub(int a,int b);
test1 a;
};
#endif // !1
但是当我们把test2.h的代码修改之后又会发现新的问题。
error C2079: “test2::a”使用未定义的 class“test1”。这里我们就要讨论一下类的前置声明和包含头文件的区别了。
类的前置声明与包含头文件的区别
类的前置声明只是告诉编译器有test1这种类型,但并没告诉编译器类的大小,成员函数,数据成员。而包含头文件则是执行到#include x.h
时,马上去编译x.h,等于说是包含头文件告诉了编译器类的所有信息(大小,成员函数,数据成员)。所以,我们也得知,前置声明只能用指针来执行,因为指针的大小在编译器上的确定的。即为在test2类中想要使用test1类的对象,对象必须是指针类型的。test1 *a;
test2.h
#ifndef __test2_H__
#define __test2_H__
#include<iostream>
#include "test1.h"
using namespace std;
class test1;
class test2
{
public:
int sub(int a,int b);
test1* a;
};
#endif // !1