C ++,循环依赖,模板和用户类型

时间:2016-06-17 13:29:39

标签: c++ function templates pointers circular-dependency

我遇到了A,B,C类之间循环依赖的麻烦。来自A类的用户类型cfunction指向C :: F1的静态方法。这是代码:

档案A.h

#ifndef A_H
#define A_H

#include "C.h"
class C;

template <typename T> using cfunction = T(*)(T, T);

template <typename T>
class A{
    public:
        cfunction <T> X;
        A () : X(&C::F1) {}
        A (const cfunction <T> &pX ) : X(pX){};
        virtual ~A() = 0;   
};
#endif

文件B.h

#ifndef B_H
#define B_H
#include "A.h"

template <typename T>
class B : public A <T> {
  public:
   B() : A<T>(), b(0.0) {}
   B(const T b_, const cfunction <T> &pX ) : A <T>(pX), b(b_){}
   virtual ~B() {};
};
#endif

最后,在C的方法init()中,存储了一个指向A的共享指针。方法F1用模板参数F3调用F2。这是代码:

档案C.h

#ifndef C_H
#define C_H

#include "A.h"
template <typename T>
class A;

#include <memory>
#include <list>

template <typename T>
using List = std::list<std::shared_ptr<A<T> > >;

//Definition of all projections
class C  {
    public:
      template <typename T, typename Function> static T F2(Function f, const T a, const T b);
      template <typename T> static void init(List<T> l);
      template <typename T> static T F1(const T a, const T b);
      template <typename T> static T F3(const T a, const T b);
};
#include "C.hpp"
#endif

档案C.hpp

#ifndef C_HPP
#define C_HPP

#include "B.h"
template <typename T>
class B;

template <typename T, typename Function> 
T C::F2(Function f, const T a, const T b) { return  f(a, b);}

template <typename T> void C::init(List<T> l) {
    auto test = std::make_shared <B < T >> (0.0, F1<T>);
    l.push_back(test);
}

template <typename T> T C::F1(const T a, const T b) {  return F2(F3<T>, a, b);}
template <typename T> T C::F3(const T a, const T b) {return a + b;}

#endif

主文件:main.cpp

#include "C.h"

int main(){
    List <double> l;
    C::init(l);
    return 0;
}

对于稍微复杂的代码感到抱歉。一个更简单的代码版本运行良好,但这个“完整”的版本罢工。我无法解决g ++的问题;编译选项:-std = c ++ 11。

感谢您的帮助......

2 个答案:

答案 0 :(得分:1)

好的,所以只需稍作调整就可以解决问题。正如您所指出的,目前您有一些循环依赖关系,但它们只能通过一个基本的略微修改来解决:即删除引用A的{​​{1}}默认构造函数。你真的不需要它 - 因为它代表你的代码不使用它。即使您这样做,也可以将C成员设置为X并稍后在外部对其进行初始化。

删除此内容后,您现在可以获得简单的包含顺序:nullptrA.hB.hC.h

在此之后我还有其他一些编译器错误需要解决:您似乎正在为一个成员启动一个不存在的C.hpp成员B。此外,即使您的b析构函数是纯虚拟的,它也需要一个定义。最终代码如下:

编辑(2):我现在修改了这个,因此不再排除A的默认构造函数。相反,只有在A的定义可用后才能在C.h中稍后定义。

A.H:

C

B.h:

#ifndef A_H
#define A_H

//#include "C.h"
//class C;

template <typename T> using cfunction = T(*)(T, T); 

template <typename T>
class A{
    public:
        cfunction <T> X;
        //A () : X(&C::F1) {}
        A ();
        A (const cfunction <T> &pX ) : X(pX){};
        virtual ~A() = 0;
};

template <typename T>
A<T>::~A() {}

#endif

C.h:

#ifndef B_H
#define B_H
#include "A.h"

template <typename T>
class B : public A <T> {
  public:
   B() : A<T>() //, b(0.0) 
   {}  
   B(const T b_, const cfunction <T> &pX ) : A <T>(pX) //, b(b_)
   {}  
   virtual ~B() {}; 
};
#endif

C.hpp:

#ifndef C_H
#define C_H

#include "A.h"
#include "B.h"

//template <typename T>
//class A;

#include <memory>
#include <list>

template <typename T>
using List = std::list<std::shared_ptr<A<T> > >;

//Definition of all projections
class C  {
    public:
      template <typename T, typename Function> static T F2(Function f, const T a, const T b); 
      template <typename T> static void init(List<T> l); 
      template <typename T> static T F1(const T a, const T b); 
      template <typename T> static T F3(const T a, const T b); 
};

template<typename T>
A<T>::A() : X(&C::F1)
{}

#include "C.hpp"
#endif

答案 1 :(得分:0)

B.h需要包含A.h(因为它需要了解其具体内容)

A.h需要包括C.h(因为它需要知道它的具体内容)。通过这样做,它不需要前向声明C,因为它已经通过包含C.h来了解它。

但是,从您的代码中,C.h 不需要来了解A的具体内容,因此无需包括A.h.相反,它可以简单地向前声明A,因为它已经在做

在类似的说明中,C.hpp不需要包含B,因为它也不需要知道B的任何细节。一个简单的前向声明(再次,你已经在做什么)就足够了

任何时候你看到自己包含一个文件并向前声明你从该文件中获得的一个类同时表明你有一些放松的事情