STL学习笔记 ---- 由set的声明所引发的自定义比较的实现方式
2010-04-23 11:17
519 查看
作者:winterTTr(转载请注明)
对于set这个STL容器来说,就实现来说,我了解到的版本,是通过RB-Tree的方式实现的,内部逻辑似乎是采用Tree结构的平行方式进行展开,换句话说也就是将Tree保存在类似vector这样的线性结构中,不过,这篇帖子并不在于讨论内部结构,而是具体使用中出现的自定义比较的几种方式。
set的话,默认情况,可以不指定第二个模板参数,但是,如果使用非基础类型的话,是需要指定第二个模板参数,用来进行比较的。
我这里以几种方式来实现,原理基本上是相同的,运行结果是完全相同的,不过实现的方式却各有特点:
重载<操作符
这种方式相对比较简单一些,针对MyClass实现全局的<操作符。因为STL的内部,基本上全部是以<操作符为基础进行比较的,对于其他的比较,按照一定得规则,全部转化为<操作符
特化less模板类
这种方式较之前者,能够提供更多的编译期信息,不过,其实原理是一样的。
注意一点:必须放入std的命名空间中,否则会报错“不在相同的命名空间”。
因为我们特化的是一个命名空间的类,而不是自己重写。
实现自己的比较对象类
当然,谁说不能自己写呢,不过,这样的话,就必须在声明的时候,显示指定比较类了。
三种方式,语言的使用上利用不同的知识点,但是,结果是完全相同的。在实际使用中,或许因为项目,代码等等诸多原因,不一定每种方法都适用,但是总应该有一种能够满足你的要求。
当然,肯定还有其他别的方式,欢迎大家补充。
对于set这个STL容器来说,就实现来说,我了解到的版本,是通过RB-Tree的方式实现的,内部逻辑似乎是采用Tree结构的平行方式进行展开,换句话说也就是将Tree保存在类似vector这样的线性结构中,不过,这篇帖子并不在于讨论内部结构,而是具体使用中出现的自定义比较的几种方式。
set的话,默认情况,可以不指定第二个模板参数,但是,如果使用非基础类型的话,是需要指定第二个模板参数,用来进行比较的。
我这里以几种方式来实现,原理基本上是相同的,运行结果是完全相同的,不过实现的方式却各有特点:
重载<操作符
#include <iostream> #include <set> using namespace std; #define INT_PTR( ptr ) ( reinterpret_cast<int>( ptr ) ) class MyClass { public: MyClass( int data ) : m_iData( data ) { cout << INT_PTR(this) << "|default constructor(" << m_iData << ")" << endl; } MyClass( const MyClass& o ) { cout << INT_PTR(this) << "|copy constructor from:" << INT_PTR(this) << "|(" << o.data() << ")" << endl; m_iData = o.data(); } ~MyClass() { cout << INT_PTR(this) << "|destructor (" << m_iData << ")" << endl; } inline int data() const { return m_iData ; } private: int m_iData; }; inline bool operator < ( const MyClass & l , const MyClass & r ) { return l.data() < r.data(); }; int main() { set<MyClass> s; s.insert( MyClass(1) ); s.insert( MyClass(3) ); s.insert( MyClass(2) ); s.insert( MyClass(1) ); return 1; }
这种方式相对比较简单一些,针对MyClass实现全局的<操作符。因为STL的内部,基本上全部是以<操作符为基础进行比较的,对于其他的比较,按照一定得规则,全部转化为<操作符
特化less模板类
#include <iostream> #include <set> using namespace std; #define INT_PTR( ptr ) ( reinterpret_cast<int>( ptr ) ) class MyClass { public: MyClass( int data ) : m_iData( data ) { cout << INT_PTR(this) << "|default constructor(" << m_iData << ")" << endl; } MyClass( const MyClass& o ) { cout << INT_PTR(this) << "|copy constructor from:" << INT_PTR(this) << "|(" << o.data() << ")" << endl; m_iData = o.data(); } ~MyClass() { cout << INT_PTR(this) << "|destructor (" << m_iData << ")" << endl; } inline int data() const { return m_iData ; } private: int m_iData; }; namespace std { template<> struct less<MyClass> { bool operator()( const MyClass & l , const MyClass & r ) const { return l.data() < r.data() ; } }; }; int main() { set<MyClass> s; s.insert( MyClass(1) ); s.insert( MyClass(3) ); s.insert( MyClass(2) ); s.insert( MyClass(1) ); return 1; }
这种方式较之前者,能够提供更多的编译期信息,不过,其实原理是一样的。
注意一点:必须放入std的命名空间中,否则会报错“不在相同的命名空间”。
因为我们特化的是一个命名空间的类,而不是自己重写。
实现自己的比较对象类
#include <iostream> #include <set> using namespace std; #define INT_PTR( ptr ) ( reinterpret_cast<int>( ptr ) ) class MyClass { public: MyClass( int data ) : m_iData( data ) { cout << INT_PTR(this) << "|default constructor(" << m_iData << ")" << endl; } MyClass( const MyClass& o ) { cout << INT_PTR(this) << "|copy constructor from:" << INT_PTR(this) << "|(" << o.data() << ")" << endl; m_iData = o.data(); } ~MyClass() { cout << INT_PTR(this) << "|destructor (" << m_iData << ")" << endl; } inline int data() const { return m_iData ; } private: int m_iData; }; struct MyClassLess: public binary_function< MyClass , MyClass , bool > { bool operator()( const MyClass & l , const MyClass & r ) const { return l.data() < r.data() ; } }; int main() { set<MyClass , MyClassLess > s; s.insert( MyClass(1) ); s.insert( MyClass(3) ); s.insert( MyClass(2) ); s.insert( MyClass(1) ); return 1; }
当然,谁说不能自己写呢,不过,这样的话,就必须在声明的时候,显示指定比较类了。
三种方式,语言的使用上利用不同的知识点,但是,结果是完全相同的。在实际使用中,或许因为项目,代码等等诸多原因,不一定每种方法都适用,但是总应该有一种能够满足你的要求。
当然,肯定还有其他别的方式,欢迎大家补充。
相关文章推荐
- ((ios开发学习笔记 十二))Nib加载的方式实现自定义TableView
- ((ios开发学习笔记 十一))自定义TableViewCell 的方式实现自定义TableView(带源码)
- STL源码学习笔记(1):stack及自定义实现
- 学习笔记:自定义方法的两种实现方式
- 安卓Studio学习笔记---gradle自定义BuildConfig.DEBUG实现在调试输出Log,正式的时候不输出Log
- Java容器学习笔记(二) Set接口及其实现类的相关知识总结
- 学习笔记之qt4程序中引入自定义窗口部件之单一继承方式
- [Animation学习笔记]Animation-动画(Frame-逐帧/Tween-补间[两种实现方式])
- 安卓学习笔记---自定义ImageView实现图片圆形 ,椭圆和矩形圆角显示(矩形圆角加边框)
- STL:set中使用自定义比较操作
- STL学习笔记6 -- 栈stack 、队列queue 和优先级priority_queue 三者比较
- SGI STL学习笔记(3):copy算法实现细节
- STL中set底层实现方式
- Android游戏开发学习笔记(一):tweened animation自定义动画的实现
- MyBatis学习笔记-Spring集成DAO层实现方式记录
- 持续集成学习笔记-入门篇(5)持续集成自动化(二):具体实现方式一
- STL学习笔记:用非递归的方法实现汉诺塔问题
- android 开发零起步学习笔记(十七):自定义android用户控件,使用回调函数实现自定义事件
- STL学习笔记----5.容器 set 和 multiset
- 《C#入门到精通》学习笔记 -- 实践: 自定义异常类的实现(2013-04-18)