问题一:临时变量具有常性问题
在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
看似两边的类型不同,本质上是由于=右边的类型与类的成员变量类型一致,因此会发生隐式类型转换。