自定义的类型放入STL的set中,需要重载自定义类中的“<”符号(转)

在以前学习STL的时候,曾经学到过,如果要将自定义的类型放入到set中的话,就需要重载“<”符号,原因是set是一个有序的集合,集合会按照“<”比较的大小,默认按照从小到大的顺序排列。假设我现在设计如下类型:

class MyType
{
public:
  int a, b, c;
}

这是,为了让MyType类型可以顺利的放进set中,我必须重载“<”,这时问题来了,要如何重载呢?这个类型有三个数据成员,我能不能要求按照a的大小排列,如果a相等的话就随便按照b或者c的大小排列呢?如果近实现按照a的大小排列的话,重载函数如下:

bool operator<(const MyType& myType) const
{
  return a<myType.a;
}

看起来简单明了,但是事实真的是这样吗?如果我声明一个set,并在其中放入MyType(1,2,3)、MyType(1,2,4)我能成功吗?实验了一下,结果如下:

测试时用的代码是这样的:

#include<iostream>
#include<set>
using namespace std;

class MyType
{
public:
  int a, b, c;
  MyType(int a, int b, int c):a(a), b(b), c(c){}
  bool operator<(const MyType& myType) const
  {
    return a<myType.a;
  }
};
int main()
{
  set<MyType> se;
  MyType type1(1,2,3);
  MyType type2(1,2,4);
  se.insert(type1);
  se.insert(type2);

  cout<<"The set size:"<<se.size()<<endl;
  cout<<"Elements in the set as follows:"<<endl;
  for(set<MyType>::iterator it = se.begin(); it != se.end(); it++)
  {
    cout<<"("<<it->a<<", "<<it->b<<", "<<it->c<<") ";
  }
  cout<<endl;
  return 0;
}

结果很明显,当我已经把MyType(1,2,3)放到set中之后,就不能把MyType(1,2,4)放进去了。但是为什么呢?这两个对象看起来确实不一样啊!STL在比较是否相同的时候不是要比较每一个数据成员的吗?从上述的例子中,看到的确实不是这样的,STL不会自动的做任何比较,它仅对你说明过的动作干一些指定的活儿。在重载“<”的时候,当只指定众多数据成员中的一部分的时候,如果这部分都相同的话,set就认为是同一个元素了。就如上述所示一样,重载的时候仅作了a的比较,而没有说明如果a相同的话,是否对剩下的元素进行比较。这样一来,set认为MyType(1,2,3)和MyType(1,2,4)是一样的。要让set正确的进行大小的比较,针对自定义类型,就必须说明所有的数据成员的比较情况。如上述的例子的“<”重载,应该这样写:

bool operator<(const MyType& myType) const
{
  return a<myType.a?true:(b<myType.b?true:c<myType.c);
}

这样一来,就完全说明了每一个数据成员的比较关系,set就可以正常工作了。还是MyType(1,2,3)、MyType(1,2,4)两个元素,这回运行的结果如下:

运行代码为:

#include<iostream>
#include<set>
using namespace std;

class MyType
{
public:
  int a, b, c;
  MyType(int a, int b, int c):a(a), b(b), c(c){}
  bool operator<(const MyType& myType) const
  {
    return a<myType.a?true:(b<myType.b?true:c<myType.c);
  }
};
int main()
{
  set<MyType> se;
  MyType type1(1,2,3);
  MyType type2(1,2,4);
  se.insert(type1);
  se.insert(type2);
  cout<<"The set size:"<<se.size()<<endl;
  cout<<"Elements in the set as follows:"<<endl;
  for(set<MyType>::iterator it = se.begin(); it != se.end(); it++)
  {
    cout<<"("<<it->a<<", "<<it->b<<", "<<it->c<<") ";
  }
  cout<<endl;
  return 0;
}

原文转自 http://www.cnblogs.com/malloc/archive/2012/03/13/2394719.html

时间: 2024-12-10 18:45:56

自定义的类型放入STL的set中,需要重载自定义类中的“<”符号(转)的相关文章

在动态sql的使用where时,if标签判断中,如果实体类中的某一个属性是String类型,那么就可以这样来判断连接语句:

如果是String类型的字符串进行判空的时候: <if test="inspectOrg != null and inspectOrg != ''"> INSPECT_ORG = #{inspectOrg} </if> 但是如果是实体类中的Integer类型,就是去掉空字符串的判断: <if test="inspectTaio != null"> AND INSPECT_TAIO = #{inspectTaio} </if&

&#39;QObject&amp; QObject::operator=(const QObject&amp;)&#39; is private——无法将自定义的QObject子类放入Qt容器(container)中

先贴出问题的代码: 1 #include<QCoreApplication> 2 classMyObject:publicQObject 3 { 4 public: 5 MyObject(QObject*parent =0): 6 QObject(parent) 7 { 8 } 9 private: 10 int m_id; 11 }; 12 int main(int argc,char*argv[]) 13 { 14 QCoreApplication a(argc, argv); 15 QL

键盘录入一个文件夹路径,统计该文件夹(包含子文件夹)中每种类型的文件及个数,注意:用文件类型(后缀名,不包含.(点),如:&quot;java&quot;,&quot;txt&quot;)作为key, 用个数作为value,放入到map集合中,遍历map集合

package cn.it.zuoye5; import java.io.File;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Scanner;import java.util.Set; /** 键盘录入一个文件夹路径,统计该文件夹(包含子文件夹)中每种类型的文件及个数,注意:用文件类型(后缀名,不包含.(点),如:"java","txt&qu

3.1将AngularJS放入上下文

本章,作者将AngularJS放在全球web app开发的上下文里,并为后面的章节设置功能.AngularJS的目标,是带来一款工具,它有服务端开发web client的能力,并易于开发,测试,富.复杂的web应用. 1.理解AngularJS擅长什么 AngularJS不是任何问题的解决方案.AngularJS的不同种类的功能,只适用于服务端开发人员,从浏览器中浏览.这意味着每次HTML文档被AngularJS加载后,都做了很多工作--HTML元素不得不被编译,数据绑定不得不被计算,指令需要被

Unity3D ShaderLab 创建自定义高光类型

Unity3D ShaderLab 创建自定义高光类型 在上一篇,我们认识了Unity基础的高光实现,本次主要是研究如何对Phong高光类型进行顶点操作,以及在表面着色器中使用Input结构体的新参数进行像素操作. 所以还是新建Shader,再建材质球然后打开编辑器进行shader的编辑. 1.修改Properties Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _MainTint("Diff

C# 注册自定义文件类型 实现自定义文件类型关联应用程序

在我们自己编写的应用中,经常会用自定义类型的文件来保存与应用相关的数据,比如.osf文件就是应用程序的项目文件.如果没有向Windows注册表注册该文件类型,那么.osf文件的图标将是windows的文件默认图标,并且你双击一个a.osf文件,也不会自动启动应用程序来加载a.osf文件.如何使.osf文件的图标变成我自己喜爱的图标.如何完成像点击.doc文件就自动打开word 程序的功能,下面将告诉你解决方案. 我们可以通过手动修改注册表来完成上述任务,更好的方式是,通过程序来实现.这样在安装应

String放入运行时常量池的时机与String.intern()方法解惑

运行时常量池概述 Java运行时常量池中主要存放两大类常量:字面量和符号引用.字面量比较接近于Java语言层面的常量概念,如文本字符串.声明为final的常量值等. 而符号引用则属于编译原理方面的概念,包括了下面三类常量: - 类和接口的全限定名(包名+类名) - 字段的名称和描述符 - 方法的名称和描述符 运行时常量池位置 运行时常量池在JDK1.6及之前版本的JVM中是方法区的一部分,而在HotSpot虚拟机中方法区放在了"永久代(Permanent Generation)".所以

[ACM] FZU 1570 集合划分问题( 不同小球放入相同盒子,第二类Stirling数)

Problem Description n个元素的集合{1,2,...,n}可以划分若干个非空子集.例如,当n=4时,集合{1,2,3,4}可以划分为15个不同的非空子集如下: {{1},{2},{3},{4}}, {{1,2},{3},{4}}, {{1,3},{2},{4}}, {{1,4},{2},{3}}, {{2,3},{1},{4}}, {{2,4},{1},{3}}, {{3,4},{1},{2}}, {{1,2},{3,4}}, {{1,3},{2,4}}, {{1,4},{2,

【算法与数据结构实战】线性表操作-实现A并B,结果放入A中

//数据结构与算法基础题1:线性表操作,实现A并B,结果放入A中 #include "stdafx.h" #include <iostream> #include <string> #include <vector> #include <algorithm> #pragma warning(disable:4996) using namespace std; int main() { vector<int> set_A, se