头文件互相包含问题

当我们有两个类的头文件互相包含时,如果出现一个类中有另一个类的对象时,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

你可能感兴趣的:(C++,头文件,前置声明)