gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 17:05:13 25 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错误。所以让我们把声明移到 本身。
    // 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/

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