我最近决定通过编写简单的结构来简化C ++开发,从而进行一些个人C ++实践。我的第一次尝试是编写一个简单的LinkedList,但将其定义为模板类,以便它可以处理多种数据类型。在这样做时,我做了标准的做法,在头文件中定义类并在cpp文件中实现它,然后我使用make来构建它(使用686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1
)。至于构建C ++文件(包括Node.cpp
,LinkedList.cpp
和LinkedListIterator.cpp
,一切正常,没有任何抱怨。然后我介绍main.cpp
,其中包含主要方法并尝试过创建一个LinkedList<string>
(有效)然后尝试调用它的长度函数,我已经定义并实现了它:
// Other code here
LinkedList<string> *list = new LinkedList<string>();
cout << "Initial length: " << list->length() << endl;
delete list;
list = NULL; // I had defined NULL to be 0, pre 4.6 compiler so nullptr wasn't available
// End the main function
这引发了一个错误,即没有为模板length()
类定义LinkedList<string>
函数,所以我开始研究,我学到了模板类不能像标准标准头/实现格式那样定义C ++类,但这些响应中没有一个(主要是在这里)解决了如何正确处理模板类。因此,为了完成我的个人练习,我删除了标题,并在cpp文件中定义并实现了类。那里的一切都很好。
有一些&#34;解决方案&#34;据说可以将实现与定义分开,例如在头文件的末尾包含cpp文件(这对我来说无法工作),或者,如果你只希望你的类使用特定类型,则声明静态模板版本在您的头文件的基础上的类,如:
// Define a template class
template LinkedList<string>;
template LinkedList<int>;
// etc...
我没有尝试过(它可能有效,而且我只是做个人运动,这是完全可以接受的)因为这只是感觉不对。如果将其锁定为某些类型,为什么要创建模板类?我意识到你可以很容易地将它锁定到你需要的所有主要类型中,为你提供一个数据类型的定义,但它并不适合我这样做。
TL; DR 最后我的问题是,在其他人会使用的某种应用程序/库中定义模板类和实现模板类的正确方法是什么?
答案 0 :(得分:3)
您需要在标题中放置所有内容 - 类定义和类代码。为了了解原因,想象一个简单的案例:
// in .hpp
template <typename T>
T increment(T x);
// in .cpp
template <typename T>
T increment(T x) { return x + 1; }
现在只编译一次.cpp。它应该为increment
函数生成什么代码? +
运算符可以是浮点加法,或整数加法,或短整数,甚至是重载operator+
。
然后考虑一下你使用 increment
函数的其他.cpp文件:
// some other .cpp file
#include "increment.hpp"
...
increment(a);
在此点,编译器知道a
是什么类型,因此它可以为increment
函数生成正确的代码。但是它不知道increment
函数的样子,因为它只看到.hpp文件而increment
的代码在 .cpp 文件中。
因此,使其工作的唯一方法是将声明和代码放在.hpp文件中,以便每次使用时,您都有定义,编译器可以生成适用于您正在使用的类型的正确版本。
答案 1 :(得分:2)
模板必须在实例化时可见。没有显式实例化,基本上意味着成员函数定义必须在标题中可供其他翻译单元实例化。