链表模板实现和运算符重载
Linked list template implementation and operators overloading
我对 C++ 中的模板还很陌生,目前在理解它们时遇到了一些困难。所以,有人给了我下一个使用模板的链表实现,运算符重载对我来说非常不清楚。这是代码:
#include <iostream>
using namespace std;
template<typename T> class List;
template <typename T>
ostream& operator<< (ostream&, const List<T>&);
template <typename T>
struct Node {
T info;
Node<T>* next;
Node (T x, Node<T>* n = nullptr) : info(x), next(n) {}
};
template <typename T>
class List {
Node<T>* first, *last;
public:
List() {
this->first = nullptr;
this->last = nullptr;
}
List (initializer_list<T> l)
{
...
}
~List();
template <typename U>
friend istream& operator >>(istream& is, List<U>& l); /// ***HERE***
friend ostream& operator<< <T> (ostream&, const List<T>&); /// ***HERE***
void insert(T,unsigned);
};
template <typename T> List <T>::~List()
{
...
}
template <typename T>
istream& operator >>(istream& is, List<T>& l)
{
Node<T>* f = l.first;
while (f != nullptr)
{
is >> f->info;
f = f->next;
}
return is;
}
template <typename T>
ostream& operator<< (ostream& out, const List<T>& l) {
Node<T>* p = l.first;
while (p != nullptr) {
out << p->info << " ";
p = p->next;
}
return out;
}
template<typename T>
void List<T>::insert(T t, unsigned x)
{
...
}
int main () {
}
他为什么使用 template <typename U>
来重载 >>
和 friend ostream& operator<< <T>
(我不确定我什至不明白 [=15] 右边的 <T>
是什么=] 表示).
我想您的问题的答案可以在 2.4 Friends 第 30 页的 C++ Templates: The Complete Guide 第二版中找到:
通常 operator >>
和 <<
为标准输入 std::istream
和输出流 std::ostream
超载,因此您可以从输入读取并写入抽象输出流。这可以在 class 之外完成,但如果在进程中访问的 class 成员是 private (就像两个指针 first
和 last
在你的例子中)要么必须使用 setter 和 getter 为它创建一个接口,要么 在 class[=52 中将运算符声明为 friend
=].通常人们会在 class 本身内部声明和定义它,但是如果出于某种原因人们希望或需要这样做,否则事情会变得有点棘手,并且 声明友元函数有两种主要方法但是之后定义它:
可以声明具有不同模板参数的新函数模板。
template <typename U>
friend istream& operator >> (istream&, List<U>&);
这就是friend istream& operator >> (istream&, List<U>&);
的实现方式。
可以前向声明class以及输出运算符
template<typename T> class List;
template <typename T>
ostream& operator << (ostream&, const List<T>&);
然后我们将非成员函数模板的特化声明为 friend(因此 <T>
)。
friend ostream& operator << <T> (ostream&, const List<T>&);
这就是friend ostream& operator << <T> (ostream&, const List<T>&);
的实现方式。
在这两种情况下,您都必须按照 class.
之外的定义来跟进声明
我没有从代码片段中看到一个比另一个更喜欢一个的真正原因:在这种情况下,它们应该是相等的。我个人实际上什至不会经历前向声明任何东西的麻烦,而是在 class 本身内部声明和定义它,因为我认为它更清楚。在我看来,应尽可能避免前向声明。
我对 C++ 中的模板还很陌生,目前在理解它们时遇到了一些困难。所以,有人给了我下一个使用模板的链表实现,运算符重载对我来说非常不清楚。这是代码:
#include <iostream>
using namespace std;
template<typename T> class List;
template <typename T>
ostream& operator<< (ostream&, const List<T>&);
template <typename T>
struct Node {
T info;
Node<T>* next;
Node (T x, Node<T>* n = nullptr) : info(x), next(n) {}
};
template <typename T>
class List {
Node<T>* first, *last;
public:
List() {
this->first = nullptr;
this->last = nullptr;
}
List (initializer_list<T> l)
{
...
}
~List();
template <typename U>
friend istream& operator >>(istream& is, List<U>& l); /// ***HERE***
friend ostream& operator<< <T> (ostream&, const List<T>&); /// ***HERE***
void insert(T,unsigned);
};
template <typename T> List <T>::~List()
{
...
}
template <typename T>
istream& operator >>(istream& is, List<T>& l)
{
Node<T>* f = l.first;
while (f != nullptr)
{
is >> f->info;
f = f->next;
}
return is;
}
template <typename T>
ostream& operator<< (ostream& out, const List<T>& l) {
Node<T>* p = l.first;
while (p != nullptr) {
out << p->info << " ";
p = p->next;
}
return out;
}
template<typename T>
void List<T>::insert(T t, unsigned x)
{
...
}
int main () {
}
他为什么使用 template <typename U>
来重载 >>
和 friend ostream& operator<< <T>
(我不确定我什至不明白 [=15] 右边的 <T>
是什么=] 表示).
我想您的问题的答案可以在 2.4 Friends 第 30 页的 C++ Templates: The Complete Guide 第二版中找到:
通常 operator >>
和 <<
为标准输入 std::istream
和输出流 std::ostream
超载,因此您可以从输入读取并写入抽象输出流。这可以在 class 之外完成,但如果在进程中访问的 class 成员是 private (就像两个指针 first
和 last
在你的例子中)要么必须使用 setter 和 getter 为它创建一个接口,要么 在 class[=52 中将运算符声明为 friend
=].通常人们会在 class 本身内部声明和定义它,但是如果出于某种原因人们希望或需要这样做,否则事情会变得有点棘手,并且 声明友元函数有两种主要方法但是之后定义它:
可以声明具有不同模板参数的新函数模板。
template <typename U> friend istream& operator >> (istream&, List<U>&);
这就是
friend istream& operator >> (istream&, List<U>&);
的实现方式。可以前向声明class以及输出运算符
template<typename T> class List; template <typename T> ostream& operator << (ostream&, const List<T>&);
然后我们将非成员函数模板的特化声明为 friend(因此
<T>
)。friend ostream& operator << <T> (ostream&, const List<T>&);
这就是
friend ostream& operator << <T> (ostream&, const List<T>&);
的实现方式。
在这两种情况下,您都必须按照 class.
之外的定义来跟进声明我没有从代码片段中看到一个比另一个更喜欢一个的真正原因:在这种情况下,它们应该是相等的。我个人实际上什至不会经历前向声明任何东西的麻烦,而是在 class 本身内部声明和定义它,因为我认为它更清楚。在我看来,应尽可能避免前向声明。