我正在创建一个仅限标头的库。在这个库中,我想使用一个稍后在头文件中定义的类。例如:
class A {
public:
int i;
A(int x) : i(x) {};
B func(B inp) {
B out(i*inp.j);
return out;
};
};
class B {
public:
int j;
B(int x) : j(x) {};
A other(A inp) {
A out(j*inp.i);
return out;
};
};
当然我的编译器不喜欢这个。它在定义func
的行上产生第一个错误:
error: unknown type name 'B'
有没有办法克服这个问题?
答案 0 :(得分:4)
一种方法是转发声明类B
,并将函数定义移出类。
通常会将定义放在源文件中,但由于它是一个仅限标题的库,您可以将函数定义标记为inline
,并且可以将其放在头文件本身中,但是在定义之后当然是B
课程。
如果B
不依赖A
,则另一种更简单的方法是将B
的定义移到上面的定义头文件中的A
。
答案 1 :(得分:4)
使用引用或指针需要相应类型的声明。使用对象(实例)或任何成员需要完整的定义或相应的类型。宣言是
class A; // declares: there is a class called 'A'
虽然定义是
class A { // (re-)declares A and defines its layout and members
/* details */
};
声明可以在定义之前(但不必使定义有效)。这立即给出了以下解决方案。
订购类 definitions ,以便以后定义的类仅在其中使用先前定义的类的对象和成员接口。例如
class A {
int i;
public:
A(int x) : i(x) {}
};
class B {
A a; // object of type A: okay, since A is defined
public:
B(int i) : a(i) {}
int foo() const {
return a.i; // member of a: okay, since A::i is defined
}
};
在任何早期声明的类中使用引用或指针的类可以转发声明(不是定义的)在任何类定义之前。例如
class B; // forward declaration of B
class A {
int i;
public:
A(int x) : i(x) {}
A(B*); // pointer to B okay, since B is declared
// cannot define A::A(B*): it depends on definition of B
};
class B {
int x;
A a; // object of type A: okay, since A is defined
public:
B(int i) : x(i+i), a(i) {}
B() : a(this);
}
定义任何依赖于声明时未知的类定义的实现细节。
inline A::A(B*b) // either inline or in a source file
: i(b->x/2) // using member B::x okay: B is defined
答案 2 :(得分:1)
不是说这是可行的方法,但是如果你对模板的一些误用很好,你可以做这样的事情(相同的例子但是删除了不相关的东西,并且如你所提到的那样使用A添加了B):< / p>
template <typename X>
struct A {
X func(X inp) { return X(/*...*/); }
};
struct B {
public:
A<B> func(A<B> inp) { return A<B>(); }
};
正如我所说,我不会这样做只是为了避免前瞻声明。另一方面,如果您确实需要循环依赖,则应重新考虑。如果两个班级相互依赖太多,你就不能接触一个而不必检查另一个班级是否没有破坏。多数民众赞成不好,如果可能,我会避免它。