我正在尝试编写一个C ++库的问题。这是通常的设置,一个cpp文件,一个头文件。我希望头文件只显示要使用的部分(例如,我有一个抽象基类,我不想在头文件中)。到目前为止,我只是处理一个文件(我认为这应该没有区别,因为包含是由预处理器完成的,它不关心任何事情。)
您会注意到“标题文件”分布在标题实现文件之前和之后的两个位置。
#include <stdio.h>
// lib.h
namespace foo {
template <class T> class A;
}
// lib.cpp
namespace foo {
template <class T> class A {
private:
T i;
public:
A(T i) {
this->i = i;
}
T returnT() {
return i;
}
};
};
// lib.h
namespace foo {
template <class T> T A<T>::returnT();
}
// foo.cpp
void main() {
foo::A<int> a = foo::A<int>(42);
printf("a = %d",a.returnT());
}
所以,当然,我希望我的头文件只包含
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
但是我的编译器不喜欢这个(它抱怨returnT
不是foo::A<T>
的成员。我不想把类声明本身放在标题中的原因是它然后它(根据我的理解),包含所有私人和类似的东西,我想隐藏。
也许只是我,但是下面的头文件似乎“糟糕”,至少作为“接口规范”。它公开了A
的一些内部结构,lib的用户不需要知道这些内容。
// lib.h
namespace foo {
template <class T> class A {
private:
int i;
public:
A(T);
T returnT();
};
}
// lib.cpp
namespace foo {
template <class T> A<T>::A(T i) {
this->i = i;
}
template <class T> T A<T>::returnT() {
return i;
}
};
这是接受的方式吗?如果可能的话,我想要一个更抽象的头文件。
答案 0 :(得分:5)
您无法将模板的定义与其声明分开。他们都必须一起进入头文件。
对于“为什么?”我建议阅读"Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?"。
我可能误解了你的问题。要解决可能也是您的问题,这是无效的:
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
由于无效的原因无效:
namespace foo {
class A;
int A::returnT();
}
必须在类的定义中声明成员函数。
答案 1 :(得分:2)
您在这里处理的.cpp文件存在两个问题:
予。 如果要将该类的实例放在堆栈上(就像在main()中那样),编译器需要知道类的大小(以分配足够的内存)。为此,它需要知道成员以及完整的声明。
隐藏类布局的唯一方法是构建一个接口和一个工厂方法/函数,并将实例放在工厂的堆上。
作为一个例子(没有模板;见下面知道原因):
namespace foo {
class IA {
public:
virtual ~IA();
virtual int returnT() = 0;
static IA *Create();
};
}
然后在.cpp中执行:
namespace foo {
class A : public IA {
private:
int i;
public:
A() :
i(0) {
}
virtual ~A() {
}
virtual int returnT() {
return i;
}
};
IA::~IA() {
}
IA *IA::Create() {
return new A();
}
}
BTW:建议使用智能指针......
II。 由于您使用的是模板,因此方法定义必须通过头文件可见,或者为特定的一组类型显式实例化。
因此,您可以将代码拆分为lib.h和lib_impl.h:
lib.h:
namespace foo {
template <typename T> class IA {
public:
virtual ~IA() {
}
virtual T returnT() = 0;
static IA *Create();
};
}
lib_impl.h:
namespace foo {
template <typename T> class A : public IA<T> {
private:
T i;
public:
A() :
i(T()) {
}
virtual ~A() {
}
virtual T returnT() {
return i;
}
};
template <typename T> IA<T> *IA<T>::Create() {
return new A<T>();
}
}
所以你需要将lib_impl.h包含在需要实现的地方。 要使用显式实例化,请添加lib.cpp并让该文件允许包含lib_impl.h:
lib.cpp:
#include <lib_impl.h>
namespace foo {
template class IA<int>;
template class A<int>;
template class IA<float>;
template class A<float>;
template class IA<char>;
template class A<char>;
// ...
}