C++ 抽象类模板 + 特定类型的子类 = 链接器有问题

Posted

技术标签:

【中文标题】C++ 抽象类模板 + 特定类型的子类 = 链接器有问题【英文标题】:C++ abstract class template + type-specific subclass = trouble with linker 【发布时间】:2010-05-05 10:18:52 【问题描述】:

有问题的项目是关于相互通信的不同端点。端点发送事件(超出当前问题的范围)并且可以处理传入事件。每个事件在一个通用对象中表示如下:

#pragma interface
... // some includes

template<typename T>
class Event

   public:
                       Event(int senderId, Type type, T payload); // Type is an enum
                       Event(int senderId, Type type, int priority, T payload);
      virtual          ~Event();
      virtual int      getSenderId();
      virtual int      getPriority();
      virtual T        getPayload();
      void             setPriority(const int priority);

   protected:
      const int        senderId;
      const Type       type;
      const T          payload;
      int              priority;
;

它的实现类带有#pragma implementation 标签。

端点定义如下:

#pragma interface
#include "Event.h"

template<typename T>
class AbstractEndPoint

   public:
                        AbstractEndPoint(int id);
      virtual           ~AbstractEndPoint();
      virtual int       getId();
      virtual void      processEvent(Event<T> event) = 0;    

   protected:
      const int         id;
;

它也有自己的实现类,但只定义了构造函数、析构函数和getId()。

这个想法是为每种不同的有效负载类型创建具体的端点。因此,我对每种类型都有不同的有效负载对象和特定的事件类,例如

Event<TelegramFormatA>, Event<TelegramFormatB>

ConcreteEndPoint for TelegramFormatA, 
ConcreteEndPoint for TelegramFormatB

分别。后面的类被定义为

class ConcreteEndPoint : AbstractEndPoint<TelegramFormatA>

    ...

我正在使用 g++ 4.4.3 和 ld 2.19。一切都编译得很好,但是链接器抱怨未定义对特定类型事件类的引用,例如

Event<TelegramFormatA>::Event(....) .

我尝试使用显式实例化

template class AbstractEndPoint<TelegramFormatA>;

但无法克服上述链接器错误。

任何想法都将不胜感激。

【问题讨论】:

【参考方案1】:

类模板的函数模板和成员函数必须在头文件中实现,而不是 .cpp 文件。我想您在 .cpp 文件中实现了Event&lt;T&gt;::Event()

【讨论】:

【参考方案2】:

正如 sbi 已经指出的那样,不允许在源文件和头文件中分离模板的接口和实现。查看此链接了解详情(页尾)http://www.cplusplus.com/doc/tutorial/templates/

【讨论】:

允许在 .cpp 文件中包含实现,但必须在头文件中#included 以便实现可见。它也不能自己编译。当它以这种方式组织时,通常会使用不同的文件扩展名(通常是 .inc)。【参考方案3】:

我刚刚找到了解决方案。信不信由你,它与 GNU 链接器 (ld) 的 v2.20 完美链接,但无法与 ld 2.19 链接。

顺便说一句

#pragma interface 

#pragma implementation

是一种特定于 g++ 的解决方法,用于解决在头文件中实现模板类的问题。使用编译指示标签可以避免它,所以这不是问题,但无论如何感谢您的建议。

【讨论】:

以上是关于C++ 抽象类模板 + 特定类型的子类 = 链接器有问题的主要内容,如果未能解决你的问题,请参考以下文章

模板模式

模板模式

模板模式

设计模式-模版方法

设计模式: 模板模式

模板方法(template pattern)