循环依赖修复

时间:2012-02-11 14:37:16

标签: c++ include circular-dependency

我确信这是我的一些设计缺陷,主要是因为我来自Java背景。但事实就是如此。

以下是一般设置:

我有一个课程,可以说A#include "B.h"

#include "B.h"

class A {

    // stuff
private:
    B _b;

}

此外,我的课程B包含#include "C.h"

#include "C.h"

class B {

    // more stuff

private:
    C::EnumType _cEnum;
}

最后我的课程C#include "A.h"

#include "A.h"

class C {
public:
    C(A a);
    enum EnumType {
        // enum stuff
    };

    // more stuff

}

我该如何解决这个问题?我已经尝试了一些前瞻性声明的业务,但它似乎没有用,虽然我没有声称我做得正确。命名空间可能吗?

3 个答案:

答案 0 :(得分:3)

在C中,你不需要包括A.只有其他两个标题需要你放在那里的include指令。

class A;

class C {
public:
    C(A a);
    enum EnumType {
        // enum stuff
    };

    // more stuff
};

C::C的定义放入.cpp文件中,然后可以包含A.h。只有C::C的定义需要其参数类型才能有定义。

答案 1 :(得分:2)

  

我尝试了一些前瞻性声明,但似乎无法正常工作

您没有向我们展示“似乎无法正常工作”,或者“它似乎无法正常工作”,但您的代码中有一个位置可以使用前向声明替换完整类型定义,而不能使用前导声明替换两个。

你不能

的地方

非静态数据成员必须是完整类型:

  

[C++11: 9.2/10]:static(9.4)数据成员不得有不完整的类型。特别是,类C不应包含类C的非静态成员,但它可以包含指向类C的对象的指针或引用。

因此,B中的AC::EnumType中的B无法向前声明。

BTW: static数据成员不是这种情况,可以向前宣布:

  

[C++11: 9.4.2/2]:在其类定义中声明static数据成员不是定义,除了cv-qualified void之外,其类型可能不完整。

你可以在哪里

但是,成员函数声明中的参数类型也是如此,因此您可以在A中转发声明C(A a)

class A;

class C {
public:
    C(A a);
    enum EnumType {
        // enum stuff
    };

    // more stuff
};

#include尽可能少地插入标题。

为什么你不需要

  

我确信这是我的一些设计缺陷,主要是因为我来自Java背景

我没有看到Java与它有任何关系但是,是的,你的设计在这些类彼此依赖的方式上似乎存在缺陷。也许C::EnumType应该是B::EnumType?尽量让你的课程更加独立。前向声明都很好,但是如果你解决了设计紧密耦合的根本问题,生活会更容易。

答案 2 :(得分:0)

@Lightness说 - 如果你使用'forward'定义声明A类,你不需要将a.h包含在C的编译单元中。只要把'A级;'进入标题,告诉编译器(和链接器)在以后确定A是什么。唯一的缺点是文件C不再知道A中的内容,所以你必须使用引用或指针。

另一种方法是将C分成两部分。嵌入其中的枚举是否有原因,而不是B的一部分?如果C和B共享枚举定义,那么它应该被拆分成一个单独的类,或者只是一个顶层的枚举。

当我得到这样的循环定义时,我会仔细检查我正在做什么。我总觉得我为自己做的事情太复杂了。