链接有问题

时间:2011-09-26 19:21:09

标签: c++ g++ linker-errors

我有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

我不明白问题所在。如果我在驱动程序文件中移动实现,那么它将编译并运行。

1 个答案:

答案 0 :(得分:3)

一般来说,模板定义也需要在头文件中。这种情况的一个例外是当您显式实例化或使用显式特化时,两者都不是。

解决此问题的一种方法是将genericStackImpl.c++的内容移动到其头文件的底部。

原因是因为模板函数不是实际函数,它们只是模板。使用(实例化)模板来创建实际的函数,这些是你链接的。

genericStackImpl.c++中没有任何功能。这些函数只有在您使用它们时才会创建,即编译器第一次看到sc.pushsc.pop。不幸的是,当driver.c++尝试创建这些函数时,它无法找到模板实体 - 它们隐藏在genericStackImpl.c++中!相反,它只是编译对这些函数的引用,希望其他文件可以创建它们。

最后,当谈到链接时,链接器无法在任何地方找到该函数,因此它会给你一个错误。

解决这个问题的另一种方法是在genericStackImpl.c++中自己明确地实例化这些函数,即

template class Stack<char>;

这将创建函数,链接器将找到它们。

这种方法的问题在于它要求您事先知道要在堆栈中使用的类型,因此大多数人只是将模板定义放在头文件中。