C++、循环依赖、模板和用户类型
C++, circular dependencies, templates and user types
我遇到了 classes A、B、C 之间的循环依赖问题。来自class 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.h页数
#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;
}
抱歉代码有点复杂。一个更简单的代码版本运行良好,但这个 "full" 变体罢工了。我无法解决 g++ 的问题;编译选项:-std=c++11.
感谢您的帮助...
B.h需要包含A.h(因为需要知道它的具体情况)
A.h 需要包括 C.h (因为它需要知道它的细节)。通过这样做,它不需要前向声明 C 因为它已经通过包含 C.h
知道它
但是,根据您的代码,C.h 不需要 了解 A 的细节,因此不需要包含 A.h。相反,它可以简单地向前声明 A,因为它已经在做
类似地,C.hpp 不需要包括 B,因为它也不需要知道 B 的任何细节。一个简单的前向声明(再一次,就像你已经在做的那样)就足够了
任何时候你看到自己包含一个文件并转发声明你同时从该文件中得到的 class 表明你有一些放松要做
好的,所以你的问题可以通过一些小的调整来解决。正如你所指出的,目前你有一些循环依赖,但它们可以通过 1 个基本和稍微修改来打破:即删除引用 C
的 A
默认构造函数。你并不真的需要它 - 因为它代表你的代码不使用它。即使您这样做了,您也可以将 X
成员设置为 nullptr
并稍后在外部对其进行初始化。
删除后,您现在可以有一个简单的包含顺序:A.h
、B.h
、C.h
、C.hpp
。
在那之后我还必须修复其他几个编译器错误:您似乎正在启动一个不存在的 B
成员 b
。此外,即使您的 A
析构函数是纯虚拟的,它也需要一个定义。最终代码如下:
EDIT(2): 我现在修改了它,因此不再排除 A
的默认构造函数。它只是稍后在 C.h
中定义,在 C
的定义可用之后。
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 ();
A (const cfunction <T> &pX ) : X(pX){};
virtual ~A() = 0;
};
template <typename T>
A<T>::~A() {}
#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.h:
#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
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
我遇到了 classes A、B、C 之间的循环依赖问题。来自class 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.h页数
#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;
}
抱歉代码有点复杂。一个更简单的代码版本运行良好,但这个 "full" 变体罢工了。我无法解决 g++ 的问题;编译选项:-std=c++11.
感谢您的帮助...
B.h需要包含A.h(因为需要知道它的具体情况)
A.h 需要包括 C.h (因为它需要知道它的细节)。通过这样做,它不需要前向声明 C 因为它已经通过包含 C.h
知道它但是,根据您的代码,C.h 不需要 了解 A 的细节,因此不需要包含 A.h。相反,它可以简单地向前声明 A,因为它已经在做
类似地,C.hpp 不需要包括 B,因为它也不需要知道 B 的任何细节。一个简单的前向声明(再一次,就像你已经在做的那样)就足够了
任何时候你看到自己包含一个文件并转发声明你同时从该文件中得到的 class 表明你有一些放松要做
好的,所以你的问题可以通过一些小的调整来解决。正如你所指出的,目前你有一些循环依赖,但它们可以通过 1 个基本和稍微修改来打破:即删除引用 C
的 A
默认构造函数。你并不真的需要它 - 因为它代表你的代码不使用它。即使您这样做了,您也可以将 X
成员设置为 nullptr
并稍后在外部对其进行初始化。
删除后,您现在可以有一个简单的包含顺序:A.h
、B.h
、C.h
、C.hpp
。
在那之后我还必须修复其他几个编译器错误:您似乎正在启动一个不存在的 B
成员 b
。此外,即使您的 A
析构函数是纯虚拟的,它也需要一个定义。最终代码如下:
EDIT(2): 我现在修改了它,因此不再排除 A
的默认构造函数。它只是稍后在 C.h
中定义,在 C
的定义可用之后。
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 ();
A (const cfunction <T> &pX ) : X(pX){};
virtual ~A() = 0;
};
template <typename T>
A<T>::~A() {}
#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.h:
#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
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