在自己实现C++中list的时候,当实现const迭代器的时候,发现报错了,一直思考到现在
才发现是一个,很简单的问题,但是也让我有了一点感受,我在这里给大家分享一下。
文章目录
- 1.当时遇到的问题
- 2.解决方法
- 3. 自己的感悟
1.当时遇到的问题
这是list的构造函数部分
这是list迭代器调用的部分。
当我运行这样一段代码的时候,会出现这样的错误:
看得更清楚一点:
而这么写的时候是没问题的:
void Print(const zsw::list<int>& ls)
{
zsw::list<int>::const_iterator cit = ls.begin();
while (cit != ls.end())
{
cout << *cit << endl;
cit++;
}
}
int main()
{
zsw::list<int> ls;
ls.push_back(1);
ls.push_back(2);
ls.push_back(3);
ls.push_back(4);
Print(ls);
//zsw::list<int>::const_iterator cit = ls.begin();
//while (cit != ls.end())
//{
// cout << *cit << endl;
// cit++;
//}
return 0;
}
我当时想不通,为什么会出现这样的问题。
我一直以为这个问题是出现在begin函数上,因为我当时想的是,我左边是const迭代器对象,begin函数有两个一个是普通版本,一个是const版本,我一直认为右边的begin函数的返回值是:
这里就出现了第一个错误,不理解函数重载的功能,调用重载函数,区别应该是体现在调用对象和传的参数上来体现。这里的ls是普通对象,所以调用的应该是普通版本的begin函数。
既然是调用的普通begin函数返回的就是普通迭代器,这就是问题的所在,我begin函数返回的的对象类型是Iterator<int, int& int*>,而对象cit的类型是Iterator<int, const int& const int*>,两者是不同的类型,而在cit的模板类实例化之后,cit是没有关于Iterator<int, int& int*>类型的构造函数的:
2.解决方法
它这里的构造函数只有用节点或者同类型的迭代器来初始化。
所以我们只需要添加这样的一个构造函数。
可以看到它是一个模板函数,这样就可以通过Iterator<int, int& int*>类型来构造Iterator<int, const int& const int*>,而这其中T1和T应该具有相似特性,为了传参正确,更严谨的写法:
上面的解决方法我是从STL中map的一个返回值理解的:
我们看到map的插入函数的参数是这样的一个,我们来看看它是什么:
其实它是一个结构体:
假如我们现在使用以下map:
它的编译的没有错误的,这显然与我们上面遇到的问题一样,map的插入函数需要的对象是pair<const key_type,mapped_type>,而对应到这里那它所需要的参数类型是pair<const string,string>,我们传的类型是pair<string, string>这又是两个不一样的类型。那么很显然解决方法就也是从这里来的:
在pair里就有这么一个模板构造函数。
可以看出这种构造函数又能充当拷贝构造又能充当构造。
3. 自己的感悟
我们在上面看到一个pair<string, string>传参给pair<const string,string>的引用,好像跟这里有点相似:
可以看到它可以编译通过。那看这个,这不就是单个内置类型的成员变量的自定义类型之间的隐式类型转换嘛,要知道内置类型在C++中也是有“构造函数”的。
再看一段代码:
template<class T1, class T2>
class A
{
public:
A()
{}
template<class N1, class N2>
A(const A<N1, N2>& a)
:_a(a._a)
, _b(a._b)
{}
T1 _a;
T2 _b;
};
void func(const A<double, double>& a)
{
cout << "void func(A<const string, string> a)" << endl;
}
int main()
{
A<int, int> a1;
func(a1);
return 0;
}
也是能编译通过的。
那这里能够实现的原因还是因为,有着隐式类型转化的作用。而隐式类型转化又有着更底层的内置类型转换(比如double转int)的构造逻辑,或者是自定义类型本身就有相关类型的构造函数(例如const char*转string)这种转化是基于两种类型具有相似的特性,所以隐式类型转换和不同类型间的构造函数是相辅相成的。
这就是基于list的const迭代器得出的一点感悟,要是错了的话,希望能够改正我。