0

我最近决定通过编写简单的结构来进行一些个人 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 文件中定义并实现了这些类。那里一切正常。

有一些“变通办法”据说可以将实现与定义分开,例如在头文件的末尾包含 cpp 文件(这对我不起作用),或者,如果你只希望你的类使用特定的类型,在头文件的基础上声明类的静态模板版本,例如:

// Define a template class
template LinkedList<string>;
template LinkedList<int>;
// etc...

我没有尝试(它可能有效,而且我只是在做个人练习,这是完全可以接受的),因为这感觉不对。如果将模板类锁定为某些类型,为什么还要创建它?我意识到您可以轻松地将其锁定为您需要的所有主要类型,为您提供几种数据类型的定义,但它不适合我以这种方式做事。

TL;DR最后我的问题是,在其他人将使用的某种应用程序/库中定义模板类和实现模板类的正确方法是什么?

4

2 回答 2

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 文件中,以便每次使用它时,您都有定义,编译器可以为您正在使用的类型生成正确的版本。

于 2013-09-26T16:53:09.607 回答
2

模板必须在实例化时可见。如果没有显式实例化,这基本上意味着成员函数定义必须在标头中可用,以供其他翻译单元实例化它。

于 2013-09-26T16:45:29.930 回答