21

类模板的虚函数可以在它的主体之外定义吗?虚函数不能内联,但为了避免编译单元中的多个定义,它们应该被标记inline(假设模板头将包含在多个源文件中)。另一方面,编译器可以随意忽略inline,所以这似乎是有效的。举个例子,下面的代码是否正确:

template <typename T>
class C
{
public:
    virtual void f(T val);
};

template <typename T>
inline
void C<T>::f(T val)
{
  //definition
}

?

BTW gcc(3.4.2)允许inline在函数定义之前省略,f(T val)但不能在常规类的类似函数之前省略。它只是gcc的行为吗?

4

3 回答 3

18

是的,即使没有inline. 它对普通成员函数和静态变量的工作方式相同:

// everything in the header:
template <class T>
class A
{
  static int i;
};

template <class T>
int A<T>::i=0;

标准报价:(3.2/5)

类类型(第 9 条)、枚举类型(7.2)、带有外部链接的内联函数(7.1.2)、类模板(第 14 条)、非静态函数模板(14.5.6)可以有多个定义、类模板的静态数据成员 (14.5.1.3)、类模板的成员函数(14.5.1.1) 或在程序中未指定某些模板参数的模板特化 (14.7, 14.5.5),前提是每个定义出现在不同的翻译单元中,并且只要定义满足以下要求...

要求基本上说这两个定义必须相同。

It doesn't work in case of regular classes. There has to be at most one definition in the whole program.

于 2012-04-18T14:22:16.753 回答
10

class您可以在定义之外,在同一个标​​头中定义模板方法,而无需使用inline也不会收到多个定义错误。

这是因为模板函数本身不会生成定义,如果它不是完全专用的。为了证明我的观点,以下内容:

void C<int>::f(int)
{
}

将导致链接器错误,因为在这种情况下函数具有定义。(前提是您将其包含在多个翻译单元中。如果您将其标记为内联:

inline void C<int>::f(int)
{
}

错误不再发生。

于 2012-04-18T14:19:12.550 回答
4

您可以在那里定义函数,只要任何需要实例化相关函数的代码在编译时(而不是链接时)都可以看到该代码。

将模板分成 2 个文件是很常见的,一个是传统的标头,第二个是实现,与非模板化函数及其实现一样。唯一的区别是当你想使用它时,你需要#include 模板实现文件以及头文件。

于 2012-04-18T14:18:53.237 回答