Dre*_*kID 11 c++ templates linked-list
编辑 - 下面回答,错过了斜角的大括号.谢谢大家.
我一直试图写一个简单的单链表,我可以在其他程序中使用.我希望它能够使用内置和用户定义的类型,这意味着它必须是模板化的.
由于这个原因,我的节点也必须模板化,因为我不知道它将要存储的信息.我写了一个节点类如下 -
template <class T> class Node
{
T data; //the object information
Node* next; //pointer to the next node element
public:
//Methods omitted for brevity
};
Run Code Online (Sandbox Code Playgroud)
我的链表类是在一个单独的类中实现的,并且在将新节点添加到列表末尾时需要实例化一个节点.我已经实现了如下 -
#include <iostream>
#include "Node.h"
using namespace std;
template <class T> class CustomLinkedList
{
Node<T> *head, *tail;
public:
CustomLinkedList()
{
head = NULL;
tail = NULL;
}
~CustomLinkedList()
{
}
//Method adds info to the end of the list
void add(T info)
{
if(head == NULL) //if our list is currently empty
{
head = new Node<T>; //Create new node of type T
head->setData(info);
tail = head;
}
else //if not empty add to the end and move the tail
{
Node* temp = new Node<T>;
temp->setData(info);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
}
//print method omitted
};
Run Code Online (Sandbox Code Playgroud)
我已经设置了一个驱动程序/测试类,如下所示 -
#include "CustomLinkedList.h"
using namespace std;
int main()
{
CustomLinkedList<int> firstList;
firstList.add(32);
firstList.printlist();
//Pause the program until input is received
int i;
cin >> i;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我在编译时遇到错误 - 错误C2955:'Node':使用类模板需要模板参数列表 - 这使我在add方法中指向以下代码行 -
Node* temp = new Node<T>;
Run Code Online (Sandbox Code Playgroud)
我不明白为什么它没有关于类型的信息,因为它在我的驱动程序类中创建时被传递到链表.我应该怎么做才能将类型信息传递给Node?
我应该创建一个私有节点结构而不是一个单独的类,并将两个类的方法组合在一个文件中吗?我不确定这会克服这个问题,但我认为可能会这样.如果可能的话,我宁愿有单独的课程.
谢谢,安德鲁.
Mat*_* M. 12
虽然答案已经提供,但我想我会添加我的盐.
在设计模板类时,最好不要在任何地方重复模板参数,以防万一您希望(有一天)更改特定细节.通常,这是通过使用typedef完成的.
template <class T>
class Node
{
public:
// bunch of types
typedef T value_type;
typedef T& reference_type;
typedef T const& const_reference_type;
typedef T* pointer_type;
typedef T const* const_pointer_type;
// From now on, T should never appear
private:
value_type m_value;
Node* m_next;
};
template <class T>
class List
{
// private, no need to expose implementation
typedef Node<T> node_type;
// From now on, T should never appear
typedef node_type* node_pointer;
public:
typedef typename node_type::value_type value_type;
typedef typename node_type::reference_type reference_type;
typedef typename node_type::const_reference_type const_reference_type;
// ...
void add(value_type info);
private:
node_pointer m_head, m_tail;
};
Run Code Online (Sandbox Code Playgroud)
最好在类声明之外定义方法,使其更容易读取接口.
template <class T>
void List<T>::add(value_type info)
{
if(head == NULL) //if our list is currently empty
{
head = new node_type;
head->setData(info);
tail = head;
}
else //if not empty add to the end and move the tail
{
Node* temp = new node_type;
temp->setData(info);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
}
Run Code Online (Sandbox Code Playgroud)
现在,几点评论:
List<T>::add将迭代器返回给新添加的对象,就像insertSTL中的方法一样(并且你可以重命名它也是如此),这将更加用户友好List<T>::add你分配内存temp然后执行一堆操作,如果有任何抛出,你已经泄露了内存setNextNull呼叫不应是必要的:的构造函数Node应该初始化所有数据成员meaningfull值,包括m_next所以这是修订版:
template <class T>
Node<T>::Node(value_type info): m_value(info), m_next(NULL) {}
template <class T>
typename List<T>::iterator insert(value_type info)
{
if (m_head == NULL)
{
m_head = new node_type(info);
m_tail = m_head;
return iterator(m_tail);
}
else
{
m_tail.setNext(new node_type(info));
node_pointer temp = m_tail;
m_tail = temp.getNext();
return iterator(temp);
}
}
Run Code Online (Sandbox Code Playgroud)
注意使用正确构造函数的简单事实如何提高我们的异常安全性:如果在构造函数期间抛出任何东西,new则需要不分配任何内存,因此没有泄漏任何内容,我们还没有执行任何操作.我们的List<T>::insert方法现在很有弹性.
最后的问题:
insert单个链接列表的常用方法在开头插入,因为它更容易:
template <class T>
typename List<T>::iterator insert(value_type info)
{
m_head = new node_type(info, m_head); // if this throws, m_head is left unmodified
return iterator(m_head);
}
Run Code Online (Sandbox Code Playgroud)
你确定要在最后使用插页吗?或者你是这样做的,因为push_back传统的矢量和列表的方法?
可能想试试
Node<T>* temp = new Node<T>;
Run Code Online (Sandbox Code Playgroud)
另外,要获得有关如何设计列表的提示,您当然可以查看std :: list,尽管有时候它可能有点令人生畏.