c++有序关联容器中键类型的约束
2017-12-02 17:29
323 查看
本文以map为例来解释有序关联容器中键类型的约束。
map是键-值对的集合,可以理解为关联数组:
运行结果:
由此可得以下两个结论:
(1) map中的元素是以键的大小顺序排序的
(2) map中不允许出现键值重复的元素
然而这也是c++中所有有序关联容器的共性。
因为map中元素要顺序存放,这也就意味着键需要具有相关的比较函数。默认情况下,标准库使用的是键类型定义的<操作符来实现键的比较的。所用的比较函数必须在键类型上实现严格弱排序(“小于”关系)。
如上代码片段自然是编译不过的:
在Number中增加<操作符重载函数。
解决办法1:在Number中增加<操作符重载函数。
尝试1:
编译:
报错”must take exactly one argument”,这是因为以成员函数的方式重载运算符,不可改变该运算符原先的参数个数: 二元运算符用成员函数重载时,只需要一个参数,另一个参数由this指针传入。
将operator<()修改为:
编译:
显然<操作符的左右操作数都要求是const的,然而在这里左操作数是非const(右操作数是const)的。所以要将该函数加上const属性:
编译运行得到正确结果:
尝试2:
二元运算符的重载函数若为非成员函数,就需要接收两个参数(左右操作数),若num是Number中的私有成员时,还需要在类中将该函数声明为友元函数:
编译运行能同样的结果。
解决办法2:将比较函数传入map
以上是方法1,下来说到的方法–自定义函数并其将作为定义map时的第三个参数(一般定义map只需要键-值两个参数)也能实现。
(1) 要将函数作为参数,自然想到用c语言中经常使用的函数指针:
(2) 再者,可以使用c++中的函数调用符号()的重载函数,即定义类仿函数:
注: 本文以map为例,但是(对键类型的约束条件)结论适用于c++中所有有序关联容器。
map是键-值对的集合,可以理解为关联数组:
std::map<int, string> map1; map1.insert(make_pair<int, string>(4, "linux")); map1.insert(make_pair<int, string>(2, "c/c++")); map1.insert(make_pair<int, string>(1, "ARM")); map1.insert(make_pair<int, string>(3, "python")); map1.insert(make_pair<int, string>(3, "java")); std::map<int, string>::iterator it = map1.begin(); while (it != map1.end()) { cout << it->first << ": " << it->second << endl; ++it; } return 0;
运行结果:
由此可得以下两个结论:
(1) map中的元素是以键的大小顺序排序的
(2) map中不允许出现键值重复的元素
然而这也是c++中所有有序关联容器的共性。
因为map中元素要顺序存放,这也就意味着键需要具有相关的比较函数。默认情况下,标准库使用的是键类型定义的<操作符来实现键的比较的。所用的比较函数必须在键类型上实现严格弱排序(“小于”关系)。
class Number{ public: int num; Number(int i) : num(i) {} }; int main(void) { Number n1(1), n2(2), n3(3), n4(4); std::map<Number, string> map2; map2.insert(make_pair<Number, string>(n4, "linux")); map2.insert(make_pair<Number, string>(n2, "c/c++")); map2.insert(make_pair<Number, string>(n1, "ARM")); map2.insert(make_pair<Number, string>(n3, "python")); std::map<Number, string>::iterator it = map2.begin(); while (it != map2.end()) { cout << (it->first).num << ": " << it->second << endl; ++it; } return 0; }
如上代码片段自然是编译不过的:
在Number中增加<操作符重载函数。
解决办法1:在Number中增加<操作符重载函数。
尝试1:
class Number{ public: int num; Number(int i) : num(i) {} bool operator< (const Number& lNumber, const Number& rNumber) { return lNumber.num < rNumber.num; } };
编译:
报错”must take exactly one argument”,这是因为以成员函数的方式重载运算符,不可改变该运算符原先的参数个数: 二元运算符用成员函数重载时,只需要一个参数,另一个参数由this指针传入。
将operator<()修改为:
bool operator< (const Number& _Number) { return this->num < _Number.num; }
编译:
显然<操作符的左右操作数都要求是const的,然而在这里左操作数是非const(右操作数是const)的。所以要将该函数加上const属性:
bool operator< (const Number& _Number) const { return this->num < _Number.num; }
编译运行得到正确结果:
尝试2:
二元运算符的重载函数若为非成员函数,就需要接收两个参数(左右操作数),若num是Number中的私有成员时,还需要在类中将该函数声明为友元函数:
class Number{ public: int num; Number(int i) : num(i) {} friend bool operator< (const Number& lNumber, const Number& rNumber); }; bool operator< (const Number& lNumber, const Number& rNumber) { return lNumber.num < rNumber.num; }
编译运行能同样的结果。
解决办法2:将比较函数传入map
以上是方法1,下来说到的方法–自定义函数并其将作为定义map时的第三个参数(一般定义map只需要键-值两个参数)也能实现。
(1) 要将函数作为参数,自然想到用c语言中经常使用的函数指针:
class Number{ public: int num; Number(int i) : num(i) {} }; bool m_comper(const Number& lNumber, c21c const Number& rNumber) { return lNumber.num < rNumber.num; } typedef bool (*pfunc)(const Number& lNumber, const Number& rNumber); int main() { Number n1(1), n2(2), n3(3), n4(4); std::map<Number, string, pfunc> map2(m_comper); //注意要将pfunc类型的函数实体为map2初始化,不然运行出现Segmentation fault map2.insert(make_pair<Number, string>(n4, "linux")); map2.insert(make_pair<Number, string>(n2, "c/c++")); map2.insert(make_pair<Number, string>(n1, "ARM")); map2.insert(make_pair<Number, string>(n3, "python")); std::map<Number, string>::iterator it = map2.begin(); while (it != map2.end()) { cout << (it->first).num << ": " << it->second << endl; ++it; } return 0; }
(2) 再者,可以使用c++中的函数调用符号()的重载函数,即定义类仿函数:
class Comp { public: bool operator() (const Number& lNumber, const Number& rNumber) { return lNumber.num < rNumber.num; } }; int main(void) { Number n1(1), n2(2), n3(3), n4(4); std::map<Number, string, Comp> map2; //使用类仿函数不需要用Comp类的实体为map2初始化 map2.insert(make_pair<Number, string>(n4, "linux")); map2.insert(make_pair<Number, string>(n2, "c/c++")); map2.insert(make_pair<Number, string>(n1, "ARM")); map2.insert(make_pair<Number, string>(n3, "python")); std::map<Number, string>::iterator it = map2.begin(); while (it != map2.end()) { cout << (it->first).num << ": " << it->second << endl; ++it; } return 0; }
注: 本文以map为例,但是(对键类型的约束条件)结论适用于c++中所有有序关联容器。
相关文章推荐
- 从一道题谈C++容器内元素的类型约束
- C++ 10.4 关联容器-----set 类型
- C++ Primer : 第十一章 : 关联容器之概述、有序关联容器关键字要求和pair类型
- C++关联容器之set类型——《C++ Primer》抄书笔记
- C++ 9.1.2 容器内元素的类型约束-------非引用、非IO标准库类型
- C++-关联容器类型map
- C++ 关联容器map 类型小结
- C++ 10.1和10.2 关联容器-----pair 类型
- C++ 有序关联容器
- C++ STL容器内元素的类型约束
- C++ 关联容器 map
- C++ 关联容器总结
- C++ vector容器类型使用
- C++ :顺序容器、关联容器
- C++容器:顺序容器,关联容器
- C++Primer第五版 第11章 关联容器(练习解答)
- IoC容器Autofac正篇之类型关联(服务暴露)(七)
- STL 关联容器 之set(无重复有序集合)
- C++ vector容器类型
- C++ vector容器类型