我经常发现自己处于这样一种情况:由于一些糟糕的设计决策(由其他人做出:),我在c++项目中面临多个编译/链接器错误,这导致了不同头文件中c++类之间的循环依赖(也可能发生在同一个文件中)。但幸运的是,这种情况发生的次数并不多,所以当下次再次发生这种情况时,我还能记住解决这个问题的方法。
因此,为了便于以后回忆,我将发布一个有代表性的问题和解决方案。更好的解决方案当然是受欢迎的。
A.h
B类;
A类
{
int _val;
B * _b;
公众:
(int val)
: _val (val)
{
}
SetB(B * B)
{
_b = b;
_b - >打印();//编译错误:C2027:使用未定义的类型“B”
}
无效的Print ()
{
cout < <“类型:val = " < < _val < < endl;
}
};
B.h
# include“A.h”
B类
{
双_val;
* _a;
公众:
B(双val)
: _val (val)
{
}
SetA(A * A)
{
_a = a;
_a - >打印();
}
无效的Print ()
{
cout < <“B型:val = " < < _val < < endl;
}
};
main.cpp
# include“B.h”
# include < iostream >
Int main(Int argc, char* argv[])
{
一个(10);
B B (3.14);
a.Print ();
a.SetB(乙);
b.Print ();
b.SetA(和);
返回0;
}
维基百科上的简单例子对我很有用。
(你可以在http://en.wikipedia.org/wiki/Circular_dependency#Example_of_circular_dependencies_in_C.2B.2B上阅读完整的描述)
文件“a.h”:
#ifndef A_H
#define A_H
class B; //forward declaration
class A {
public:
B* b;
};
#endif //A_H
文件“b.h”:
#ifndef B_H
#define B_H
class A; //forward declaration
class B {
public:
A* a;
};
#endif //B_H
文件“main.cpp”:
#include "a.h"
#include "b.h"
int main() {
A a;
B b;
a.b = &b;
b.a = &a;
}
如果从头文件中删除方法定义,并让类只包含方法声明和变量声明/定义,就可以避免编译错误。方法定义应该放在.cpp文件中(就像最佳实践指南所说的那样)。
以下解决方案的缺点是(假设您已经将方法放在头文件中以内联它们)编译器不再内联这些方法,并且尝试使用内联关键字会产生链接器错误。
//A.h
#ifndef A_H
#define A_H
class B;
class A
{
int _val;
B* _b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
//B.h
#ifndef B_H
#define B_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
//A.cpp
#include "A.h"
#include "B.h"
#include <iostream>
using namespace std;
A::A(int val)
:_val(val)
{
}
void A::SetB(B *b)
{
_b = b;
cout<<"Inside SetB()"<<endl;
_b->Print();
}
void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
//B.cpp
#include "B.h"
#include "A.h"
#include <iostream>
using namespace std;
B::B(double val)
:_val(val)
{
}
void B::SetA(A *a)
{
_a = a;
cout<<"Inside SetA()"<<endl;
_a->Print();
}
void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
//main.cpp
#include "A.h"
#include "B.h"
int main(int argc, char* argv[])
{
A a(10);
B b(3.14);
a.Print();
a.SetB(&b);
b.Print();
b.SetA(&a);
return 0;
}