问题一:临时变量具有常性问题
在list中具体的场景:
在list中,iterator迭代器被封装成了类,iterator类中有 operator!= 这一重载函数
template <class T> struct __list_iterator { typedef list_node<T> Node;//结点重命名为Node __list_iterator(Node* node) :_node(node) {} bool operator!=( __list_iterator& it) { return _node!= it._node; } Node* _node; };
//iterator本质上还是一个指向Node类型的指针。
调用 operator!=
tsj::list<int> lt1; lt1.push_back(1); lt1.push_back(2); lt1.push_back(3); tsj::list<int>::iterator it = lt1.begin(); while (it != lt1.end()) { (*it) += 1; cout << *it << " "; ++it; } cout << endl;
编译器会报错,如下:
我们不是写了!=的重载函数吗?报错说不匹配,那么只可能是参数不匹配。
实参是:lt1.end() ,形参是:__list_iterator& it
end()函数如下:
template <class T> class list { public: typedef __list_iterator<T> iterator; typedef list_node<T> Node; list() { _head = new Node; _head->_prev = _head; _head->_next = _head; } iterator end() { return _head->_prev; } private: Node* _head; };
函数的返回方式有两类,一类是传值返回,一类是传引用返回。这里是传值返回。
传值返回的特点是,返回值会被寄存到一个临时对象中,函数调用结束后临时对象的内容再赋值给函数调用处,且临时对象具有常性。
那么问题找到了,end()的 返回值具有常性,而形参__list_iterator& it不具有常性。因此二者的类型不匹配,所以编译器才会报如上错误。
解决方法就是在__list_iterator& it前加上const。
问题二:单参数的构造函数支持隐式类型转换
仍然是end()函数
_head->_prev 是指针,返回类型却是iterator,很显然二者类型不同。那他为什么可以传回去呢?上述过程等价于 __list_iterator& it=_head->_prev;上文已经提到,end()是传值返回,_head->_prev 的内容被存放到一个临时对象中,然后传递给__list_iterator& it,会调用__list_iterator中的拷贝构造函数,而拷贝构造函数的形参与_head->_prev类型一致。
对这部分总结一下:单参数的构造函数支持隐式类型转换 ,形如 __list_iterator& it=_head->_prev
看似两边的类型不同,本质上是由于=右边的类型与类的成员变量类型一致,因此会发生隐式类型转换。