1.情景还原
今天我在复习list的时候, 我随手写了下面代码,
zzg::list<int> l; //第二种
l = { 1, 2, 3 };
但是问题是, 我没有实现以initializer_list为参数的赋值运算符重载函数啊???竟然还能能跑, 这是什么情况???
2.问题分析与解答
首先, 我们来看下面两种调用形式:
zzg::list<int> l = { 1, 2, 3 }; //第一种zzg::list<int> l; //第二种
l = { 1, 2, 3 };
我们分别来说一下调用逻辑, 如果是第一种, 就是直接构造. 调用的函数是:
但是第二种, 就有个问题了. 我现在实现的构造和赋值函数如下: 即无参构造\拷贝构造\initializer_list构造\赋值运算函数重载以及析构函数
我们假定赋值运算符函数用的是传统写法, 即与上图一致, 把现代写法屏蔽掉.
这样写就直接过不了编译阶段. 因为我们没有实现参数匹配的赋值运算符函数重载.
但是我们如果换成现代写法呢? 是可以正常跑的. 因为隐式类型转换之后赋值运算符函数重载的参数匹配了.
这是因为, 代码zzg::list l; 先调用无参构造, 即list(), 之后l = { 1, 2, 3 };调用赋值现代写法, 我们的现代写法参数是list, 此时list会去调用initializer_list构造, 构造出赋值运算符函数现代写法中的参数list, 然后就可以正常跑了.
3.总结
我们总结一下, 就是我随便写了以下代码, 结果能跑令我很疑惑???这什么情况???
疑惑的点在于, 我明明没有写第二行代码能够调用的对应的赋值函数啊?怎么可以跑呢?
这是因为我当时用的是赋值函数重载的现代写法, 恰好利用了list的隐式类型转换, 即第二行代码调用传统写法的赋值函数, 然后又调用了initializer_list为参数的构造来构造了一个list参数对象, 之后就可以跑了.
但是如果用的是现代写法的传统写法, 就会不能跑, 因为参数用的是引用, 不能匹配.
4.参考代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;namespace zzg
{template<class T>struct ListNode{public:T _data;struct ListNode<T>* _prev;struct ListNode<T>* _next;public:ListNode(const T& t = T()):_data(t),_prev(nullptr),_next(nullptr){}};template<class T, class Ref, class Ptr>//这里Ref, 即Reference引用的意思, 而Ptr, 指的是pointer, 即指针的意思class List_Iterator{typedef ListNode<T> node;typedef List_Iterator<T, Ref, Ptr> Self;public:node* _ptr;public://构造函数List_Iterator(node* node):_ptr(node){}//++iteratorSelf& operator++(){_ptr = _ptr->_next;return *this;}//iterator++Self operator++(int){Self it(_ptr);//构建临时局部对象. _ptr = _ptr->_next;return it;}//--iteratorSelf& operator--(){_ptr = _ptr->_prev;return *this;}//iterator--Self operator--(int){Self it(_ptr);_ptr = _ptr->_prev;return it;}//*iterator//T& operator*()//const T& operator*()Ref operator*(){return _ptr->_data;}//iterator->//T* operator->()//const T* operator->()Ptr operator->(){return &(_ptr->_data);}//it1 != it2bool operator!=(const List_Iterator<T, Ref, Ptr> l){return _ptr != l._ptr;}//it1 == it2bool operator==(const List_Iterator<T, Ref, Ptr> l){return _ptr == l._ptr;}};//template<class T>//class Const_List_Iterator//{// typedef ListNode<T> node;// typedef Const_List_Iterator Self;//public:// node* _ptr;//public:// //构造函数// Const_List_Iterator(node* node)// :_ptr(node)// {}// //++iterator// Self& operator++()// {// _ptr = _ptr->_next;// return *this;// }// //iterator++// Self operator++(int)// {// Self it(_ptr);//构建临时局部对象. // _ptr = _ptr->_next;// return it;// }// //--iterator// Self& operator--()// {// _ptr = _ptr->_prev;// return *this;// }// //iterator--// Self operator--(int)// {// Self it(_ptr);// _ptr = _ptr->_prev;// return it;// }// //*iterator// const T& operator*()//这个地方也需要带const// {// return _ptr->_data;// }// //iterator->// const T* operator->()//const T* ptr, 这个的意思是不能*ptr// {// return &(_ptr->_data);// }// //it1 != it2// bool operator!=(const Const_List_Iterator<T> l)// {// return _ptr != l._ptr;// }// //it1 == it2// bool operator==(const Const_List_Iterator<T> l)// {// return _ptr == l._ptr;// }//};template<class T>class list{typedef ListNode<T> node;public:typedef List_Iterator<T, T&, T*> iterator;typedef List_Iterator<T, const T&, const T*> const_iterator;private:node* _head;public://构造函数list(){cout << "list()" << endl;empty_initialization();}void empty_initialization(){_head = new node();_head->_prev = _head;_head->_next = _head;}//拷贝构造函数list(const list<T>& l){empty_initialization();for (auto& e : l){push_back(e);}}//initializer_list构造函数list(initializer_list<T> il){empty_initialization();//申请一个哨兵位cout << "list(initializer_list<T> il)" << endl;for (auto& e : il){this->push_back(e);}}//赋值运算符函数//list<T>& operator=(const list<T>& l)//{// clear();//清理原有的资源// for (auto& e : l)// {// push_back(l);// }// return *this;//}//赋值运算符函数重载, 现代写法list<T>& operator=(list<T> l){//swapnode* head = _head;_head = l._head;l._head = head;return *this;}//析构函数~list(){clear();//释放资源delete _head;//释放_head指向的哨兵位资源_head = nullptr;//把_head置空}//迭代器iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}//const迭代器const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}//插入在pos位置之前. void insert(const iterator& pos, const T& data){node* newnode = new node(data);node* cur = pos._ptr;//指向当前结点node* prev = pos._ptr->_prev;cur->_prev = newnode;newnode->_next = cur;newnode->_prev = prev;prev->_next = newnode;newnode = nullptr;}void push_back(const T& t){insert(end(), t);}void push_front(const T& t){insert(begin(), t);}//删除iterator erase(const iterator& pos){node* cur = pos._ptr;node* prev = pos._ptr->_prev;node* next = pos._ptr->_next;prev->_next = next;next->_prev = prev;free(cur);return iterator(next);//构造指向下一个结点的迭代器返回}iterator pop_back(){erase(--end());}iterator pop_front(){erase(begin());}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}size_t size(){size_t number = 0;node* cur = _head;while (cur->_next != _head){number++;cur = cur->_next;}return number;}bool empty(){return size() == 0;}};void test_list1(){zzg::list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);zzg::list<int>::iterator it = l.begin();while (it != l.end()){std::cout << ((*it) += 7) << std::endl;it++;}}void test_list2(){zzg::list<int> l;cout << "empty : " << l.empty() << endl;l.insert(l.end(), 1); // 1l.insert(l.end(), 2); // 1 2l.insert(l.end(), 3); // 1 2 3l.push_front(4); //4 1 2 3l.push_back(5); //4 1 2 3 5for (auto e : l){cout << e << endl;}cout << "size : " << l.size() << endl;cout << "empty : " << l.empty() << endl;}struct A{int _a;int _b;A(int a = 0, int b = 0):_a(a),_b(b){}};void func_test3(const list<A>& l){zzg::list<A>::const_iterator it = l.begin();while (it != l.end()){cout << (it->_a) << " : " << (it->_b) << endl;it++;}}void test_list3(){/*zzg::list<A> l;for (int i = 0; i < 6; i++){l.push_back({ i, i });}zzg::list<A>::iterator it = l.begin();while (it != l.end()){cout << (*(it))._a << " : " << (*it)._b << endl;cout << (it->_a) << " : " << (it->_b) << endl;cout << it.operator->()->_a << " : " << it.operator->()->_b << endl;it++;}*//*const zzg::list<A> l;zzg::list<A>::const_iterator it = l.begin();while (it != l.end()){cout << it->_a << " : " << it->_b << endl;it++;}*///这样测试有个大问题, 就是没数据, const list不能插入数据啊..., 想要调用const迭代器还必须得用const list//有个好的办法就是让const list去做一个函数参数. zzg::list<A> l;for (int i = 0; i < 10; i++){l.push_back({i, i});}func_test3(l);}void test_list4(){//zzg::list<int> l = { 1, 2, 3 };zzg::list<int> l;l = { 1, 2, 3 };/*zzg::list<int> cl;cl = l;for (auto e : l){cout << e << endl;}cout << "---------" << endl;for (auto e : cl){cout << e << endl;}*/}
};
#include"list.h"int main()
{//zzg::test_list1();//zzg::test_list2();//zzg::test_list3();zzg::test_list4();return 0;
}
EOF