【问题标题】:CRTP, forward declarations and templates in cpp filescpp 文件中的 CRTP、前向声明和模板
【发布时间】:2013-04-08 13:29:22
【问题描述】:

我正在使用 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();
}

这是实现接口的实现

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

有什么解决方法吗?谢谢。

【问题讨论】:

  • 在界面中进行前向声明是这里的重点,如果不是这样,我会将所有内容移动到头文件中。
  • 使用模板 interface 定义和指针可以实现您正在尝试做的事情(如果我理解的话,那是不确定的),但是像这样的实例级我我很难看到它起作用。

标签: c++ templates design-patterns crtp


【解决方案1】:

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

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

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

【讨论】:

  • 是的,在阅读 parashift 的常见问题解答后不久修复了它,因为你的答案是正确的,你得到了积分:)
【解决方案2】:

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

【讨论】:

  • 是的,但如果我这样做,我必须#include "ForwardDecl.h" 并且 this 是我试图避免的。
猜你喜欢
  • 1970-01-01
  • 2022-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多