派生类在基类中调用模板函数时链接问题

时间:2011-09-29 06:22:37

标签: c++ inheritance linker-errors template-function

我在base.h中有一个 Base 类,它有一个模板函数

class Base {
 template <typename T> void test(T a);
}

这个模板应该是intdouble类型的读物,我有派生类,它来自 Base < / p>

我试图在类Derived中调用函数测试,但是我有链接器错误。

最后,我意识到如果在base.cpp中,我会添加

void test(int a);
void test(double a);

不会出现编译错误。这个解决方案看起来很尴尬,有更好的解决方案吗?谢谢

3 个答案:

答案 0 :(得分:3)

C ++模板必须在定义(给定一个完整的函数体)在相同的翻译单元(.CPP文件加上所有包含的头文件)中使用它们。在您的头文件中,您所做的只是声明(给定名称和签名)函数。结果是,当您包含base.h时,所有编译器都会看到:

class Base {
  template <typename T> void test(T a);
}

这声明但没有定义函数。要定义它,您必须包含一个函数体:

class Base {
  template <typename T> void test(T a)
  {
    // do something cool with a here
  }
}

需要这样做的原因是C ++编译器在“按需”的基础上为模板生成代码。例如,如果您致电:

Base obj;
obj.test< int >( 1 );
obj.test< char >( 'c' );

编译器将根据Base::test模板生成两组机器代码,一组用于int,另一组用于char。这里的限制是Base::test模板的定义必须在同一个翻译单元(.CPP文件)中,否则编译器将不知道如何为{{1}的每个版本构建机器代码功能。编译器一次只能在一个翻译单元上运行,因此不知道您是否在某个其他CPP文件中定义了Base::test。它只能与手头的东西一起使用。

这与泛型在C#,Java和类似语言中的工作方式完全不同。我个人认为模板是一个文本宏,可以根据需要由编译器进行扩展。这迫使我要记住,模板函数的完整主体需要包含在使用它的任何CPP文件中。

答案 1 :(得分:2)

您必须先完全定义模板函数test才能使用它。最简单的方法是在base.h

的标题中编写函数体
class Base {
 template <typename T> void test(T a)
 {
    ... function body here
 }
}

答案 2 :(得分:0)

如果在基类中声明模板函数,这意味着它在编译时获取模板参数但是如果你尝试通过派生类访问,这是运行时实现,那么在运行时提供的编译时模板请求是不可能的,并且主要的是c ++不支持这个。