gpt4 book ai didi

c++ - 解决由于类之间的循环依赖而导致的构建错误

转载 作者:行者123 更新时间:2023-11-28 08:34:39 26 4
gpt4 key购买 nike

我经常发现自己处于这样的情况下,由于一些错误的设计决策(由其他人做出的:)导致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错误。因此,让我们将声明移至A.h本身。

// 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;
}


HTH。

关于c++ - 解决由于类之间的循环依赖而导致的构建错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59430511/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com