C++怎么让两个头文件相互包含?

两个类分别声明在两个头文件中,这两个类需要通过【直接】【相互】控制进行协作。【直接】指的是不能使用管理类进行控制;【相互】指的是相互调用对方的方法。因此两个头文件需要相互包含。两个头文件应该怎样写才不会报“重定义”、“未定义标识符”、“无法解析的外部符号”之类的错误?
特别地,如果两个类都是泛型的,由于编译器的原因,类的实现和声明必须都写在头文件中。这种情况下怎样相互包含?
(最好有例子,给出头文件的代码)

    可以通过预处理宏来控制重复包含的问题

    如果是模板类,那么类成员函数声明为内联的即可

 例如
 //A.h
 #pragma once

#include "B.h"

template<typename T> class B; 

template<typename T> class A
{
public:
A(B<T>* b=NULL):b_(b){};

void SetPtr(B<T>* b)
{
b_ = b;
}

void CallFuncFromB()
{
b_->PrintfB();
}

void PrintfA()
{
cout<<"PrintfA"<<endl;
}

public:
B<T>* b_;
};

//B.h
#pragma once

#include "A.h"

template<typename T> class A;

template<typename T> class B
{
public:
B(A<T>* a=NULL):a_(a){}

void SetPtr(A<T>* a)
{
a_ = a;
}

void CallFuncFromA()
{
a_->PrintfA();
}

void PrintfB()
{
cout<<"PrintfB"<<endl;
}

public:
A<T>* a_;
};

//main.cpp
#include <iostream>
#include "A.h"

using namespace std;

int main(int argc, char** argv)
{
A<int> a;
B<int> b;

a.SetPtr(&b);
b.SetPtr(&a);

a.CallFuncFromB();
b.CallFuncFromA();

system("pause");

return 0;
}

//这种方法有一种限值条件,就是模板类A和B的模板参数要求一致。

追问

用#pragma once会不会导致下列问题:
一个头文件先被执行;然后这个头文件被包含,但是因为#pagma once,里面的声明不会再执行一遍,结果导致“未声明标识符”

内联是指inline吗?为什么内联就行了?

追答

或者你都不include对方的头文件,直接前置声明也一样的

内联就是inline ,为什么要内联这是由于当时C++98标准没有解决这一问题而编译器厂家委婉的一种做法,具体google之。

追问

1.首先感谢你~那段代码能用。
直接前置声明,如template class B; 不包含头文件,那不就没有声明成员函数吗?这样也能调用B的方法?
另外能不能再给一个例子:一个类泛型,另一个类不泛型。

2.加上inline解决什么问题?解决不能相互包含,还是解决泛型类的实现和声明不能分开?如果比较长的函数,编译器不会按照内联来编译,这样还有效吗?

追答

    模板类只有在实例化的时候才去找成员函数的定义,在main.cpp里POI(初始化点)的时候是能找到双方的函数定义的(你include了)

    inline是大多数编译器厂家的做法,叫做包含模型(这样在头文件里加入inline后就可包含实现),因为当时要实现export的分离模型很难,现在最新的C++11应该实现了该做法

    再给你一个例子吧 记得结贴哦!




//C.h
#pragma once

#include "D.h" 

template<typename T> class C
{
public:
C(D* d=NULL):d_(d){};

void SetPtr(D* d)
{
d_ = d;
}

void CallFuncFromD()
{
d_->PrintfD();
}

void PrintfC()
{
cout<<"PrintfC"<<endl;
}

typedef T CT;
private:
D* d_;
};

//D.h
#pragma once

class D
{
public:
D(void* c=NULL):c_(c){}

void SetPtr(void* c)
{
c_ = c;
}

void PrintfD()
{
std::cout<<"PrintfD"<<std::endl;
}

template<typename T>
void CallFuncFromC()
{
C<T>* p = static_cast<C<T>*>(c_);
p->PrintfC();
}

private:
void* c_;
};

//main.cpp
#include <iostream>
#include "C.h"

using namespace std;

int main(int argc, char** argv)
{
C<int> c;
D d;
c.SetPtr(&d);
d.SetPtr(&c);
c.CallFuncFromD();
d.CallFuncFromC<C<int>::CT>();

system("pause");

return 0;
}

一个模板,一个非模板  非模板的一定要声明为模板成员函数才能调用模板类的方法!切记!

温馨提示:答案为网友推荐,仅供参考
第1个回答  2014-06-13
互相包含绝对是不行,这会导致包含产生一个类似递归的死循环,既然互相包含不行那么肯定有一方是不可能知道对方的实现细节的,也就不可能通过对象.成员的方式来调用.但是你可以尝试使用回调函数和管理类(已被否决)的方式来解决该问题.追问

从功能内聚的角度上,两个类都有自己专用的属性和方法。如果使用回调,不就没法把一组[实现相同目标]的功能和它们需要的数据一起封装到一个模块了?

第2个回答  2015-09-10
在头文件用下面的宏把代码包起来, 这样可以防止重复。 你说的相互包含,没有问题的啊。

#ifndef _FILENAME_H
#define _FILENAME_H

#endif