2

我正在使用 CRTP 模式创建一个接口,其他类将从该接口派生。

在界面中,我转发声明了一个结构(很重要,因为我不想在界面中拖动其他东西),但我将其定义包含在定义界面的 cpp 文件中。

接口.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

接口.cpp

#include "Interface.h"
#include "ForwardDecl.h"

template<class Derived>
ForwardDecl Interface<Derived>::interfaceMethod()
{
    return static_cast<Derived *>(this)->implementation_func();
}

这是实现接口的实现

实现.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

实现.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 上都遇到链接错误。

任何解决方法?谢谢你。

4

2 回答 2

1

函数模板的定义和类模板的成员函数需要在实例化这些模板的所有翻译单元中可见。也就是说,您不应该将模板定义放在.cpp文件中,这意味着您需要将Interface.cppup 的内容移动到Interface.h.

于 2013-04-08T13:30:56.493 回答
1

您的方法有一个缺陷:您有一个返回 ForwardDecl 实例的公共函数,因此每个想要使用此函数的客户端还必须包含该类型的相应定义,这意味着您可以从一开始就将该类型设为公共。这包括使函数定义内联,这将解决您的链接器问题。

但是,如果您真的想隐藏该结构的内容并且您确定客户端不需要直接使用它,您可以声明它,然后传递对这种结构的引用(或指针,但原始指针是邪恶的,尽管不在与#macros 相同的邪恶联盟)。在这种情况下,我仍然会将函数定义内联。

如果你真的不想让函数内联,你也可以显式地为你需要的类型实例化函数模板。您可以在模板的 .cpp 文件的末尾添加类似的内容template class Interface<int>;(我不记得确切的语法,因此请使用一些 fleur de sel,查看parashift.com 上的 C++ FAQ 以获取更多信息)。这使得模板不太通用,因为它需要针对您想要使用它的任何类型进行调整,但在某些极端情况下它可能是一种方法。

于 2013-04-08T21:07:55.977 回答