如何在 c++ 链表中使用模板?
How to use templates in a c++ linked list?
我不完全理解模板的概念,并试图获得有关如何在下面的链表上实现模板的帮助。我正在尝试让我的代码能够支持以下类型List< List<std::string> >
List<std::string>
List<int>
:我想知道除了尝试解释正在发生的事情之外,是否有人可以给我一个例子,说明如何将这些项目转换为模板?我是 c++ 的新手,所以我能得到的任何帮助将不胜感激。
#include <string>
#include <iostream>
#include <cstddef>
using Item = std::string;
// TURN DList into a template!
class DList {
private:
class DListNode {
public:
Item item;
DListNode * next;
DListNode * prev;
DListNode(Item i, DListNode *n=nullptr, DListNode *p=nullptr) {
item = i;
next = n;
prev = p;
}
};
DListNode * head;
DListNode * tail;
public:
class iterator {
DListNode *node;
public:
iterator(DListNode *n = nullptr) {
node = n;
}
Item& getItem() { return node->item; }
void next() { node = node->next; }
void prev() { node = node->prev; }
bool end() { return node==nullptr; }
friend class DList;
};
public:
DList() {
// list is empty
head = nullptr;
tail = nullptr;
}
bool empty() {
return head==nullptr;
}
void append(Item a) {
DListNode *node = new DListNode(a,nullptr,tail);
if ( head == nullptr ) {
// empty list
head = node;
tail = node;
} else {
tail->next = node;
tail = node;
}
}
void insertAfter(iterator it, Item item)
{
if(head == nullptr || it.node == nullptr) { // NULL iterator means insert at head
DListNode *node = new DListNode(item,head); // next=head, prev=NULL
if ( head == nullptr) // same as zyBook
head = tail = node;
else { // if inserting before head, it.node==NULL
head->prev = node;
head = node;
}
} else if (it.node == tail) {
DListNode *node = new DListNode(item,nullptr,tail); // next=NULL, prev=old tail
tail->next = node;
tail = node;
} else {
DListNode *node = new DListNode(item,it.node->next,it.node);
it.node->next = node;
node->next->prev = node;
}
}
void erase (iterator it) {
DListNode *succ = it.node->next; // successor node
DListNode *pred = it.node->prev; // predecessor node
if (succ != NULL)
succ->prev = pred;
if (pred != NULL)
pred->next = succ;
if (it.node == head)
head = succ; // head is following node
if (it.node == tail)
tail = pred; // tail is previous node
delete it.node; // delete the node; not shown in zyBook, but necessary in C/C++
// iterator is now invalid, caller should not use it again
}
iterator begin() {
return iterator(head);
}
iterator reverse_begin() {
return iterator(tail);
}
};
template <typename Item>
std::ostream& operator << (std::ostream& out, DList<Item> &l)
{
out << "{";
auto it = l.begin();
out << it.getItem();
it.next();
for(; !it.end(); it.next())
{
out << ", " << it.getItem();
}
out << "}" << std::endl;
return out;
}
int main()
{
{
DList<std::string> l;
l.append("eggs");
l.append("milk");
l.append("bread");
std::cout << l;
}
{
DList<int> l;
l.append(1);
l.append(2);
l.append(3);
std::cout << l;
}
return 0;
}
实际上,您几乎拥有所需的一切,但您仍在使用具有具体类型的 regualar 类。
using Item = std::string;
class DList { ... };
所以首先我们去掉具体类型:
// using Item = std::string;
class DList { ... }; // sure Item is now undefined...
然后我们告诉类是一个模板
template <typename Item>
class DList { ... };
现在Item
被重新引入,但它现在不是具体类型,而是通用类型。就是这样,你有一个模板列表(假设列表正确实现,我没有检查(。
现在,每当您实例化列表时:
DList<int>;
DList<std::string>;
// ...
你创建了一个全新的、独立的数据类型(这尤其意味着,你不能将DList<int>
分配给指向DList<double>
的指针,就像你不能将 int 分配给指针到双精度一样(。
当您实例化模板时,每次出现的模板参数都将替换为您实例化模板的类型,例如,在DList<int>
中,每次出现Item
都将替换为int
。
好吧,所有这些都只是一个非常简短的介绍,还有很多事情要做,但这更像是在书中处理,而不是在堆栈溢出的答案中处理......
不过,对节点构造函数的一些说明:
DListNode(Item i /* , ... */) { item = i; }
首先,您应该习惯于使用构造函数的初始化器列表(不要与std::initializer_list
混淆(:
DListNode(Item i /* , ... */) : item(i) { }
您可以避免默认的启动 + 赋值,而是按值直接初始化。此外,某些类型(非默认可构造类型、const 成员和引用(只能以这种方式初始化。
然后,您将生成不必要的副本:
DListNode(Item i /* , ... */) : item(i) { }
// ^ temporary copy ^ final copy, created from temporary
如果您通过引用接受该项目,则可以避免该副本:
DListNode(Item const& i /* , ... */) : item(i) { }
// now copies from reference, one copy less
您还可以提供移动语义:
DListNode(Item&& i /* , ... */) : item(std::move(i)) { }
这样,您不再需要的列表之外的对象就可以移动到其中(好吧,实际上是它们的内容(。在某些情况下,这可能比完整副本便宜得多......
关于构造函数的所有内容(除了初始化器列表(也适用于append
和insertAfter
函数。
初始化器列表和避免复制是一般建议,与模板无关......
- 反向给定链表中的K节点
- 如果没有malloc,链表实现将失败
- 文本文件中的单词链表
- 努力将整数转换为链表。不知道我在这里做错了什么
- 链表,反向函数,数据结构
- 使用std::list创建循环链表
- 链表的泛型函数remove()与成员函数remove)
- 为什么不能修改对象中的值?另外,我如何改进此链表?
- 我们可以删除链表中静态内存中的节点吗
- C++,指针数组,指向双链表中的条目
- 链表中写入访问冲突的未知原因
- 如何修复链表类实现的未处理异常0xDDDDDDDD
- 打印所有链表的元素 (C++)
- 错误:需要类名(链表c++)
- 为什么C中的通用链表中存储的数据已损坏
- C++ 创建包含链表和字符串的对象的链接列表时出错
- 链表c++插入,所有情况都已检查,但没有任何工作
- 链表,将列表复制到另一个列表
- 为什么C++对链表中的下一个节点使用指针,而像 C# 或 Java 这样的语言只使用类 Node 的名称?
- 对单向链表进行排序时出现运行时错误