使用模板将堆栈实现为链接列表时出现 "symbols not found" 错误
Getting "symbols not found" errors implementing a Stack as Linked List using templates
我正在尝试使用链表创建堆栈。我已经使用整数让它工作了,但现在我想为它实现模板。编译前没有检测到错误,但在 运行 之后我得到这些错误:
*未定义的体系结构符号x86_84:
"Stack::printStack()",引用自:
_main main.o
"Stack::pop()",引用自:
_main main.o
"Stack::push(int)",引用自:
_main main.o
"Stack::~Stack()",引用自:
_main main.o
ld:未找到体系结构的符号 x86_64
clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
*
我认为我的麻烦来自于必须定义两个模板,一个在 Stack.h 文件中,一个在我的 LinkedList.h 文件中。在我的 Stack.h 文件中,我需要调用 Node,如果不包含模板参数我就无法调用 Node,如果我不包含另一个模板定义,Stack.h 将无法识别模板参数。现在有些情况下我只使用 'T' 而不是 Node,但我已经尝试了两种方法。我觉得我已经尝试了一切,但我无法弄清楚我的错误在哪里。在这一点上,我真的只是为了概念证明,这就是为什么我没有为 Stack 添加复制构造函数或其他函数的原因。我的代码如下。
LinkedList.h
#ifndef Linked_List__Stack_LinkedList_h
#define Linked_List__Stack_LinkedList_h
template<class T>
struct Node {
public:
Node(Node *n, T data) : next(n), data(data) {}
Node *getNext() const { return next; }
T value() const { return data; }
private:
Node* next;
T data;
};
#endif
Stack.h
#ifndef __Linked_List__Stack__Stack__
#define __Linked_List__Stack__Stack__
#include "LinkedList.h"
#include <stdio.h>
#include <iostream>
using namespace std;
template <class T>
class Stack {
public:
Stack() : head(NULL), tail(NULL) {};
~Stack();
void push(T data);
T pop();
void printStack();
private:
Node<T> *head;
Node<T> *tail;
};
#endif /* defined(__Linked_List__Stack__Stack__) */
Stack.cpp
#include "Stack.h"
template <class T>
Stack<T>::~Stack() {
while (head) {
Node<T>* temp = head->getNext();
delete head;
head = temp;
}
head = tail = NULL;
}
template <class T>
void Stack<T>::push(T data) {
Node<T>* node = new Node<T>(head, data);
head = node;
if (head->getNext() == NULL )
tail = head;
}
template <class T>
T Stack<T>::pop() {
Node<T> *top = head;
T data;
if(head == NULL)
throw; //StackError(E_EMPTY);
data = head->value();
head = head->getNext();
delete top;
return data;
}
template <class T>
void Stack<T>::printStack() {
Node<T> *current = head;
while (current != tail) {
cout << current->value() << ", ";
current = current->getNext();
}
cout << current->value() << endl;
}
main.cpp
#include "Stack.h"
#include <iostream>
#include <stdexcept>
int main(int argc, const char * argv[]) {
Stack<int> *myIntStack = new Stack<int>();
myIntStack->push(10);
myIntStack->printStack();
myIntStack->pop();
myIntStack->printStack();
delete myIntStack;
return 0;
}
几乎没有流行的编译器允许您将模板定义作为单独的编译单元放在 cpp 文件中(因此出现链接器错误)。
简而言之,只需将您的 Stack.cpp 的内容移至 Stack.h(并忘记您的 Stack.cpp),然后一切都应该有效。
我喜欢使用的另一种方式(好吧...十多年前,当我还在工作中编写 C++ 时)是 "include" header 中的模板源,例如:
Foo.h
#ifndef FOO_H__
#define FOO_H__
TEMPLATE_DECL template <class T> Foo {
....
};
#ifndef SUPPORT_TEMPLATE_EXPORT
#include "Foo.tmpl" // include it if you CANNOT compile it as separate compilation unit
#endif
#endif //ifndef FOO_H__
Foo.tmpl(我使用另一个扩展名来区别于.cpp)
#ifdef SUPPORT_TEMPLATE_EXPORT
#include "Foo.h" // only include if you can compile it as separate compilation unit
#endif
// template definition
TEMPLATE_DEF Foo<T>::bar() {....}
当然,您需要注意预处理器和编译器设置,但这应该是微不足道的。而且,模板导出从 C++0x 开始被弃用,如果您不关心在旧编译器(例如 Comenu)中使用此功能,则可以进一步简化此方法
一些东西 off-topic:避免在你的 header 中使用名称空间(或实际上任何 using 子句)。会造成命名空间污染
正如 Adrian 指出的那样,编译器需要在实例化时拥有所有可用的模板实现,我同意他的建议,只需将实现移至 Stack.h
.
但是,如果您出于自己的目的想要将接口和实现分开,您可以 #include "Stack.cpp"
在 Stack.h
的底部(并从 [=14] 中删除 #include "Stack.h"
=]).
我正在尝试使用链表创建堆栈。我已经使用整数让它工作了,但现在我想为它实现模板。编译前没有检测到错误,但在 运行 之后我得到这些错误:
*未定义的体系结构符号x86_84: "Stack::printStack()",引用自: _main main.o
"Stack::pop()",引用自: _main main.o
"Stack::push(int)",引用自: _main main.o
"Stack::~Stack()",引用自: _main main.o
ld:未找到体系结构的符号 x86_64 clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用) *
我认为我的麻烦来自于必须定义两个模板,一个在 Stack.h 文件中,一个在我的 LinkedList.h 文件中。在我的 Stack.h 文件中,我需要调用 Node,如果不包含模板参数我就无法调用 Node,如果我不包含另一个模板定义,Stack.h 将无法识别模板参数。现在有些情况下我只使用 'T' 而不是 Node,但我已经尝试了两种方法。我觉得我已经尝试了一切,但我无法弄清楚我的错误在哪里。在这一点上,我真的只是为了概念证明,这就是为什么我没有为 Stack 添加复制构造函数或其他函数的原因。我的代码如下。
LinkedList.h
#ifndef Linked_List__Stack_LinkedList_h
#define Linked_List__Stack_LinkedList_h
template<class T>
struct Node {
public:
Node(Node *n, T data) : next(n), data(data) {}
Node *getNext() const { return next; }
T value() const { return data; }
private:
Node* next;
T data;
};
#endif
Stack.h
#ifndef __Linked_List__Stack__Stack__
#define __Linked_List__Stack__Stack__
#include "LinkedList.h"
#include <stdio.h>
#include <iostream>
using namespace std;
template <class T>
class Stack {
public:
Stack() : head(NULL), tail(NULL) {};
~Stack();
void push(T data);
T pop();
void printStack();
private:
Node<T> *head;
Node<T> *tail;
};
#endif /* defined(__Linked_List__Stack__Stack__) */
Stack.cpp
#include "Stack.h"
template <class T>
Stack<T>::~Stack() {
while (head) {
Node<T>* temp = head->getNext();
delete head;
head = temp;
}
head = tail = NULL;
}
template <class T>
void Stack<T>::push(T data) {
Node<T>* node = new Node<T>(head, data);
head = node;
if (head->getNext() == NULL )
tail = head;
}
template <class T>
T Stack<T>::pop() {
Node<T> *top = head;
T data;
if(head == NULL)
throw; //StackError(E_EMPTY);
data = head->value();
head = head->getNext();
delete top;
return data;
}
template <class T>
void Stack<T>::printStack() {
Node<T> *current = head;
while (current != tail) {
cout << current->value() << ", ";
current = current->getNext();
}
cout << current->value() << endl;
}
main.cpp
#include "Stack.h"
#include <iostream>
#include <stdexcept>
int main(int argc, const char * argv[]) {
Stack<int> *myIntStack = new Stack<int>();
myIntStack->push(10);
myIntStack->printStack();
myIntStack->pop();
myIntStack->printStack();
delete myIntStack;
return 0;
}
几乎没有流行的编译器允许您将模板定义作为单独的编译单元放在 cpp 文件中(因此出现链接器错误)。
简而言之,只需将您的 Stack.cpp 的内容移至 Stack.h(并忘记您的 Stack.cpp),然后一切都应该有效。
我喜欢使用的另一种方式(好吧...十多年前,当我还在工作中编写 C++ 时)是 "include" header 中的模板源,例如:
Foo.h
#ifndef FOO_H__
#define FOO_H__
TEMPLATE_DECL template <class T> Foo {
....
};
#ifndef SUPPORT_TEMPLATE_EXPORT
#include "Foo.tmpl" // include it if you CANNOT compile it as separate compilation unit
#endif
#endif //ifndef FOO_H__
Foo.tmpl(我使用另一个扩展名来区别于.cpp)
#ifdef SUPPORT_TEMPLATE_EXPORT
#include "Foo.h" // only include if you can compile it as separate compilation unit
#endif
// template definition
TEMPLATE_DEF Foo<T>::bar() {....}
当然,您需要注意预处理器和编译器设置,但这应该是微不足道的。而且,模板导出从 C++0x 开始被弃用,如果您不关心在旧编译器(例如 Comenu)中使用此功能,则可以进一步简化此方法
一些东西 off-topic:避免在你的 header 中使用名称空间(或实际上任何 using 子句)。会造成命名空间污染
正如 Adrian 指出的那样,编译器需要在实例化时拥有所有可用的模板实现,我同意他的建议,只需将实现移至 Stack.h
.
但是,如果您出于自己的目的想要将接口和实现分开,您可以 #include "Stack.cpp"
在 Stack.h
的底部(并从 [=14] 中删除 #include "Stack.h"
=]).