我经常发现自己在 C++ 项目中面临多个编译/链接器错误的情况,由于一些糟糕的设计决策(由其他人:))导致不同头文件中的 C++ 类之间的循环依赖(也可能发生)在同一个文件中)。但幸运的是(?)这不会经常发生,让我记住下一次再次发生时解决这个问题的方法。
所以为了以后方便记忆,我将发布一个有代表性的问题和一个解决方案。更好的解决方案当然是受欢迎的。
A.h
class B;
class A
{
int _val;
B *_b;
public:
A(int val)
:_val(val)
{
}
void SetB(B *b)
{
_b = b;
_b->Print(); // COMPILER ERROR: C2027: use of undefined type 'B'
}
void Print()
{
cout<<"Type:A val="<<_val<<endl;
}
};
B.h
#include "A.h"
class B
{
double _val;
A* _a;
public:
B(double val)
:_val(val)
{
}
void SetA(A *a)
{
_a = a;
_a->Print();
}
void Print()
{
cout<<"Type:B val="<<_val<<endl;
}
};
main.cpp
#include "B.h"
#include <iostream>
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;
}
最佳答案
思考这个问题的方法是“像编译器一样思考”。
想象一下,您正在编写一个编译器。你会看到这样的代码。
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
编译时 .cc 文件(记住 .cc 而不是 .h 是编译单位),你需要为对象
A
分配空间.那么,那么,有多少空间呢?足以存放B
! B
的尺寸是多少然后?足以存放A
!哎呀。显然,您必须打破循环引用。
您可以通过允许编译器保留尽可能多的空间来打破它,例如,指针和引用将始终为 32 位或 64 位(取决于体系结构),因此如果您将(任一)替换为一个指针或引用,事情会很棒。假设我们在
A
中替换:// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
现在情况好多了。有些。
main()
仍然说:// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include
, 对于所有范围和目的(如果您将预处理器取出)只需将文件复制到 .cc .真的, .cc 好像:// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
你可以看到为什么编译器不能处理这个 - 它不知道是什么
B
是 - 它以前甚至从未见过这个符号。所以让我们告诉编译器关于
B
.这被称为 forward declaration ,并在 this answer 中进一步讨论.// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
这有效。这不是很好。但是此时您应该了解循环引用问题以及我们为“修复”它所做的工作,尽管修复很糟糕。
这个修复不好的原因是因为下一个人
#include "A.h"
必须申报 B
在他们可以使用它之前会得到一个可怕的#include
错误。所以让我们把声明移到 啊本身。// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
而在 B.h ,此时,您只需
#include "A.h"
直接地。// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
哈。
关于c++ - 解决由于类之间的循环依赖导致的构建错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70178855/