我有3个C ++文件: genericStack.h:
template <class T>
class Stack{
public:
Stack (int size){
top = -1;
MAX_SIZE = size;
v = new T (size);
}
~Stack(){ delete v;}
T pop();
void push (T);
class Underflow{};
class Overflow{};
private:
int top;
int MAX_SIZE;
T* v;
};
genericStackImpl.c ++:
#include "genericStack.h"
template <class T>
void Stack <T> :: push (T c){
if (top == MAX_SIZE - 1) throw Overflow();
v[++top] = c;
}
template <class T>
T Stack <T> :: pop(){
if (top < 0) throw Underflow();
return v[top--];
}
driver.c ++:
#include <iostream>
#include "genericStack.h"
int main(){
Stack<char> sc(3);
try{
while (true) sc.push ('p');
}
catch (Stack<char>::Overflow){std::cout << "Overflow caught\n";}
try{
while (true) std::cout << sc.pop() << '\n';
}
catch (Stack<char>::Underflow){ std::cout << "Underflow caught\n";}
return 0;
}
当我使用g ++ 4.5编译时:
g++ -o driver driver.c++ genericStackImpl.c++
我收到这些错误:
/tmp/ccLXRXgF.o: In function `main':
driver.c++:(.text+0x2e): undefined reference to `Stack<char>::push(char)'
driver.c++:(.text+0x3c): undefined reference to `Stack<char>::pop()'
collect2: ld returned 1 exit status
我不明白问题所在。如果我在驱动程序文件中移动实现,那么它将编译并运行。
答案 0 :(得分:3)
一般来说,模板定义也需要在头文件中。这种情况的一个例外是当您显式实例化或使用显式特化时,两者都不是。
解决此问题的一种方法是将genericStackImpl.c++
的内容移动到其头文件的底部。
原因是因为模板函数不是实际函数,它们只是模板。使用(实例化)模板来创建实际的函数,这些是你链接的。
genericStackImpl.c++
中没有任何功能。这些函数只有在您使用它们时才会创建,即编译器第一次看到sc.push
和sc.pop
。不幸的是,当driver.c++
尝试创建这些函数时,它无法找到模板实体 - 它们隐藏在genericStackImpl.c++
中!相反,它只是编译对这些函数的引用,希望其他文件可以创建它们。
最后,当谈到链接时,链接器无法在任何地方找到该函数,因此它会给你一个错误。
解决这个问题的另一种方法是在genericStackImpl.c++
中自己明确地实例化这些函数,即
template class Stack<char>;
这将创建函数,链接器将找到它们。
这种方法的问题在于它要求您事先知道要在堆栈中使用的类型,因此大多数人只是将模板定义放在头文件中。