我使用CRTP模式创建一个接口,其他类将从中派生出来。
在接口中我转发声明一个结构(很重要,因为我不想在界面中拖动其他内容),但我将其定义包含在定义接口的cpp文件中。
Interface.h
#ifndef INTERFACE_H_INCLUDED
#define INTERFACE_H_INCLUDED
// forward declaration
class ForwardDecl;
template <class Derived>
class Interface
{
public:
ForwardDecl interfaceMethod();
};
#endif // INTERFACE_H_INCLUDED
ForwardDecl.h
#ifndef FORWARDDECL_H_INCLUDED
#define FORWARDDECL_H_INCLUDED
struct ForwardDecl
{
ForwardDecl(int i):internal(i)
{}
int internal;
};
#endif // FORWARDDECL_H_INCLUDED
Interface.cpp
#include "Interface.h"
#include "ForwardDecl.h"
template<class Derived>
ForwardDecl Interface<Derived>::interfaceMethod()
{
return static_cast<Derived *>(this)->implementation_func();
}
这是实现接口的实现
Implementation.h
#ifndef IMPLEMENTATION_H_INCLUDED
#define IMPLEMENTATION_H_INCLUDED
#include "Interface.h"
class ForwardDecl;
class Implementation: public Interface<Implementation>
{
friend class Interface<Implementation>;
private:
ForwardDecl implementation_func();
};
#endif // IMPLEMENTATION_H_INCLUDED
Implementation.cpp
#include "Implementation.h"
#include "ForwardDecl.h"
#include <iostream>
struct ForwardDecl Implementation::implementation_func()
{
ForwardDecl fd(42);
std::cout << fd.internal << std::endl;
return fd;
}
主文件
#include <iostream>
#include "Implementation.h"
#include "ForwardDecl.h"
using namespace std;
int main()
{
Implementation impl;
ForwardDecl fd = impl.interfaceMethod();
cout << fd.internal << endl;
return 0;
}
我在VS和GCC上都有链接错误。
任何解决方法?谢谢。
答案 0 :(得分:1)
类模板的函数模板和成员函数的定义需要在实例化这些模板的所有翻译单元中可见。也就是说,您不应将模板定义放在.cpp
文件中,这意味着您需要将Interface.cpp
的内容移至Interface.h
。
答案 1 :(得分:1)
你的方法有一个缺陷:你有一个返回ForwardDecl实例的公共函数,所以每个想要使用这个函数的客户端也必须包含该类型的相应定义,这意味着你可以从该类型公开该类型开始。这包括使函数定义内联,这将修复链接器问题。
但是,如果你真的想要隐藏该结构的内容并且你确定客户端不需要它直接,你可以声明它然后传递对这样一个结构(或指针,但原始指针是邪恶的)的引用虽然与#macros不在同一个邪恶联盟中。在这种情况下,我仍然会将函数定义内联。
如果你真的,真的不想使函数内联,你也可以显式地为你需要的类型实例化函数模板。你可以在模板的.cpp文件的末尾添加类似template class Interface<int>;
的内容(我不记得确切的语法,所以只需要一些fleur de sel,请查看C++ FAQ at parashift.com for more info)。这使得模板不那么通用,因为它需要调整您想要使用它的任何类型,但它可能是某些极端情况下的方法。