我对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>
(我甚至不确定我是否理解<<
右边的<T>
是什么意思(。
我想你的问题的答案可以在C++模板:完整指南的第二版2.4 Friends第30页上找到:
通常,operator >>
和<<
对于标准输入std::istream
和输出流std::ostream
是过载的,因此您可以从输入中读取并写入抽象输出流。这可以在类之外完成,但如果进程中访问的类成员是private(如示例中的两个指针first
和last
(,则必须为其创建一个带有setter和getter的接口,或者在类内部将运算符声明为friend
。通常情况下,人们会在类本身中声明和定义它,但如果出于某种原因,人们希望或需要做其他事情,事情就会变得有点棘手,有两种主要的方法可以声明朋友函数,但随后定义它:
-
可以用不同的模板参数来声明一个新的函数模板。
template <typename U> friend istream& operator >> (istream&, List<U>&);
这就是
friend istream& operator >> (istream&, List<U>&);
的实现方式。 -
可以正向声明类以及输出运算符
template<typename T> class List; template <typename T> ostream& operator << (ostream&, const List<T>&);
然后我们将非成员函数模板的专业化声明为朋友(因此使用
<T>
(。friend ostream& operator << <T> (ostream&, const List<T>&);
这就是
friend ostream& operator << <T> (ostream&, const List<T>&);
的实现方式。
在这两种情况下,您都必须通过类外的定义来跟进声明。
从代码片段中,我看不出喜欢其中一个而不是另一个的真正原因:在这种情况下,它们应该相等。实际上,我个人甚至不会经历向前声明任何东西的麻烦,而是会在类本身中声明和定义它,因为我认为它要清楚得多。我认为,应尽可能避免前瞻性声明。