链表模板实现和运算符重载



我对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(如示例中的两个指针firstlast(,则必须为其创建一个带有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>&);的实现方式。

在这两种情况下,您都必须通过类外的定义来跟进声明。

从代码片段中,我看不出喜欢其中一个而不是另一个的真正原因:在这种情况下,它们应该相等。实际上,我个人甚至不会经历向前声明任何东西的麻烦,而是会在类本身中声明和定义它,因为我认为它要清楚得多。我认为,应尽可能避免前瞻性声明。

相关内容

  • 没有找到相关文章

最新更新