在C ++模板类中存在循环依赖时修复包含的顺序

时间:2012-07-09 11:21:52

标签: c++ circular-dependency

我遇到了循环依赖问题,其中包含标题的顺序很重要。 This问题类似,但它没有记录一个类实例化另一个对象的解决方案。

问题:

  • 我有两个班:Foo和Bar。酒吧是模板化的。 (Foo可能会也可能不会被模板化)。
  • Foo有一个Bar实例,Bar有一个Foo类型的指针,Bar的实现需要通过这个指针访问Foo的成员。
  • Foo和Bar必须在单独的文件中实施。由于Bar是模板化的,它的声明和实现必须在同一个文件中。

在下面的代码中,如果main.cpp在Foo.h之前包含Bar.h,则代码编译,而在Bar.h之前包含Foo.h时则不会。 有没有办法让代码编译,而不管main.cpp中包含头的顺序是什么?

foo.h中

#ifndef FOO_H
#define FOO_H

#include"Bar.h"
class Foo
{
    public:
        Bar<> B;
        void fooStuff(){};

};
#endif

Bar.h

#ifndef BAR_H
#define BAR_H

class Foo;
template<int N=0> class Bar
{
    public:
        Foo * F;
        void barStuff();
};

#include"Foo.h"
 template<int N> void Bar<N>::barStuff()
{
        F->fooStuff();
};
#endif

的main.cpp

#include"Foo.h"
#include"Bar.h"
int main()
{
    Foo F;
    F.B.barStuff();
};

2 个答案:

答案 0 :(得分:4)

是:在Foo之前声明Bar,因为Bar仅使用指针,而不需要完整定义。然后在Foo之后定义Bar - 它使用一个对象,因此它确实需要定义。

class Foo;

template<int N> class Bar
{
    public:
        Foo * M;
        void barStuff();
};

class Foo
{
    public:
        Bar<42> B;
        void fooStuff(){}
};

template<int N> void Bar<N>::barStuff()
{
    M->fooStuff();
}

通常,您需要对需要该类的任何属性的任何内容(例如其大小或成员)的完整定义,以及在声明函数,指针或引用时仅使用类名称的声明。

答案 1 :(得分:2)

我需要在Foo之前​​包含Bar,无论它们包含在main.cpp中的顺序如何。以下黑客似乎有效:

在Foo.h中,包括Bar.h 之外的标题保护。由于Bar也有头球防守,所以不会多次被包括在内。

<强> foo.h中

#include"Bar.h"

#ifndef FOO_H
#define FOO_H


class Foo
{
    public:
        Bar<> B;
        void fooStuff(){};

};
#endif

<强> Bar.h

#ifndef BAR_H
#define BAR_H

class Foo;
template<int N=0> class Bar
{
    public:
        Foo * F;
        void barStuff();
};

#include"Foo.h"
 template<int N> void Bar<N>::barStuff()
{
        F->fooStuff();
};
#endif

<强>的main.cpp

#include"Foo.h"
#include"Bar.h"
int main()
{
    Foo F;
    F.B.barStuff();
};