1.情景还原
今天我在复习list的时候, 我随手写了下面代码,
cpp
zzg::list<int> l; //第二种
l = { 1, 2, 3 };
但是问题是, 我没有实现以initializer_list为参数的赋值运算符重载函数啊???竟然还能能跑, 这是什么情况???
2.问题分析与解答
首先, 我们来看下面两种调用形式:
cpp
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.参考代码
cpp
#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)
{}
//++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
//T& operator*()
//const T& operator*()
Ref operator*()
{
return _ptr->_data;
}
//iterator->
//T* operator->()
//const T* operator->()
Ptr operator->()
{
return &(_ptr->_data);
}
//it1 != it2
bool operator!=(const List_Iterator<T, Ref, Ptr> l)
{
return _ptr != l._ptr;
}
//it1 == it2
bool 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)
{
//swap
node* 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); // 1
l.insert(l.end(), 2); // 1 2
l.insert(l.end(), 3); // 1 2 3
l.push_front(4); //4 1 2 3
l.push_back(5); //4 1 2 3 5
for (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