我正在学习C ++并且它并不是一种愉快的体验(至少与Java或VBA相比)。我有以下代码:
//This is in a number.h file
#pragma once
template <class T>
class number{
public:
T value1, value2, result;
public:
T add();
number(T value1_in, T value2_in);
};
//This is in a number.cpp file
template <class T>
number<T>::number(T value1_in, T value2_in){
value1 = value1_in;
value2 = value2_in;
}
template <class T>
T number<T>::add(){
result = value1 + value2;
return result;
}
//This is in main.cpp
#include "number.h"
#include <iostream>
using namespace std;
int main(){
int a = 2, b =3;
number<int> n1(a,b);
cout << n1.add();
system("pause");
return EXIT_SUCCESS;
}
这当然给了我一个错误。虽然我很确定它应该有效。更具体地说,我收到链接器错误。经过3个小时的讨论,我决定在main.cpp中包含number.cpp,并且神奇地使它工作。这到底是怎么回事?我以为我只需要包含头文件(在此之前我为不同的算法编写了一组带有一系列线性求解器的矩阵类,并且只在整个项目中包含了头文件)。这个C ++是特定的还是特定于编译器的? (我正在使用Dev-C ++ 4.9.9.2,其中有Mingw我猜)
答案 0 :(得分:3)
模板化的类或函数总是需要保留在头文件中。
原因是无论何时实例化模板,预处理器(内部编译器)都会为这种实例化生成新代码(例如number<double>
)。这就是为什么类number<double>
和number<int>
不会共享任何关系:它们将是两个完全不同的类,尽管它们都是从同一个模板生成的。
为使编译器能够生成此代码,它必须知道整个模板定义,而不仅仅是其声明。这就是模板需要完整保留在标题中的原因。
在main.cpp中包含cpp文件就可以了,因为它实际上变成了一个标题。
答案 1 :(得分:3)
你不必须将整个定义放入头文件中;不要听别人告诉你的事情: - )
这是传统的解决方案,你和我会经常这样做,但它不是唯一的解决方案。
另一个选项是简单地将此行放在number.cpp文件的 end 中,以强制实例化该特定模板类并在那里完全编译。
template class number<int>;
简而言之,有两种有效的解决方案。您可以使用此行,也可以将定义复制到头文件中。根据上下文,一种方法可能比另一种方法更好,但两者都是有效的。请参阅我的这个答案,以便对这两种方法进行更全面的讨论:
答案 2 :(得分:2)
在C ++中,模板就像它们的名字所暗示的那样:类,函数等的模板。因为模板参数的具体类型事先是未知的,并且编译的目标代码取决于实际参数,所以它们不是得到编译(作为普通的类和函数),直到你在任何其他源文件中使用它们,并且编译器知道它应该替换为模板参数的类型。
这就是为什么必须在头文件中定义和实现所有函数的原因。 有关详细说明,请参阅this documentation的最后一部分或this similar question的答案。