IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 实现自定义类的find_if STL 重载运算符 -> 正文阅读

[C++知识库]C++ 实现自定义类的find_if STL 重载运算符

C++ vector/STL 实现自定义类的查找 find_if()

问题描述

在实际问题中,我们常常会定义vector,或者其他容器,用来存储“基本数据类型”(int,float,string,…),但是有时候我们也会用到“自定义数据类型”(类,结构体)。

struct my_struct{
	int a;
	int b;
};

class my_class{
public:
	my_struct _m;
};

这个时候我们就需要用到

vector<my_stuct> vecMyStruct;
vecotr<my_class> vecMyClass;

如果我们想要查找vector中的某一个元素的位置,或者一个元素是否在vector中,通常会用到 #include <algorithm> 头文件中的 find 函数或者 find_if 函数。对于基本数据类型,我们会通常会这么查找:

vector<int> vecInt;
vector<int>::iterator first = vecInt.begin();
vector<int>::iterator last = vecInt.end();
vector<int>::iterator pos = find(first,last,5);//查找值为5的元素,返回值是iterator
if(pos != last)
	cout<<"find!"<<endl;
else
	cout<<"not find~"<<endl;

这种查找有其局限性,那么如果我们需要查找自己定义的类的对象呢?比如:

vector<my_class> vecMyClass 中查找 my_class obj
find(first,last,?)

这个时候就不能使用find函数,要使用find_if函数,本篇文章就仔细讲一下find_if函数查找自己定义的类,以及find_if函数的原理。

find_if函数源码分析

在cpp参考手册中http://www.cplusplus.com/reference/algorithm/find_if/?kw=find_if
我从该网址转载一下函数的源码,这个网址是我学习C++经常查找函数时所用到的,很不错的网站。

template<class InputIterator, class UnaryPredicate>
  InputIterator find_if (InputIterator first, InputIterator last, UnaryPredicate pred)
{
  while (first!=last) {
    if (pred(*first)) return first;
    ++first;
  }
  return last;
}

通俗来讲,该函数的意思是,把迭代器从头到尾访问一遍,符合pred()函数中的条件的元素,返回它,我们需要做的就是自己定义一个pred()函数,里面实现我们要查找的功能,具体这个pred函数该如何写呢,这就是我们需要考虑到的了。举个例子:

准备一下数据
vector<my_struct> v;
v.push_back(my_struct(1, 2));//我在struct里写了构造函数,在后面的代码贴出
v.push_back(my_struct(2, 3));
v.push_back(my_struct(4, 5));
my_struct obj(2,3);

准备在v中查找obj这个元素

我们先从基本的数据类型里入手吧,循序渐进的来解决问题:
先看看如果只是查找my_struct结构体中,成员a=2的元素

my_struct.a == 2

我们可以这么做:

定义一个compare函数
bool compare(const my_struct& s)
{
	return s.a == 2;
}

如果这个对象s的成员a的值是2,那么返回true,否则返回false,把这个函数代入到find_if函数中看一下:

vector<my_struct>::iterator first = v.begin();
vector<my_struct>::iterator last = v.end();
vector<my_struct>::iterator pos;
pos = find_if(first,last,compare);

在find_if函数里面:
find_if (first, last, compare)
{
  while (first!=last) {
    if (compare(*first)) return first;
    ++first;
  }
  return last;
}

进一步展开来看:
find_if (first, last, compare)
{
  while (first!=last) {
    if (*first.a==2) return first;
    ++first;
  }
  return last;
}

众所周知first也就是迭代器iterator, *first就是取当前元素的值,等同于对一个my_struct s对象s.a取值
当前对象的a成员值为2的时候,就返回first(当前位置)了。否则返回end。

这么来看,其实查找的还是一个基本数据类型,如果我想查找的就是my_struct呢?我想查找一个obj(上文代码段中提到)是否在其中,怎么设计这个compare函数呢?

想象一下
bool compare(const my_struct& s)
{
	bool b1 = s.a == obj.a;
	bool b2 = s.a == obj.b;
	return b1&&b2;
}

在这里我们虽然只能传一个参数,也就是s,我们的obj无从得来呀~
而且find_if(first,last,func) 中的func只接受一个参数,且用这个参数来遍历vector中的各个元素

这个时候我们找不到其他方式引入obj,但如果obj就是成员的一个呢?所以这里就联想到了类,里面可以定义一个my_struct类型的成员,把这个类取名叫Find:

class Find{
public:
	my_struct _m;
	Find(my_struct m):_m(m){}//构造函数
	bool operator()(const my_struct& m1)//重载运算符
	{
		return (_m.a==m1.a)&&(_m.b==m1.b);
	}
};

经过前人总结,重载运算符这一步叫做“仿函数",为什么这么设计,我们把它代入到find_if函数中来解读一下:

find_if(first,last,Find(obj));
在这里调用了构造函数,创建了Find对象,其成员_m已被赋值为obj,这个对象的名字没有给出,咱们叫他tmp
这个tmp对象代入到find_if函数中

-->
find_if(first,last,Find(obj))
{
//Find(obj)相当于 Find tmp = Find(obj)
	while (first!=last) {
    if (tmp(*first)) return first;  在这里调用了重载过的'()'运算符
    ++first;
  }
  return last;
 }
【注意🐖】:这里的Find(obj))不是把Find放进pred所代表的地方,而是这一句产生的对象tmp,放到pred所对应到的地方,切记
否则会把运算符重载和构造函数弄混的。

-->tmp(*first)展开
{
	return (_m.a==*first.a)&&(_m.b==*first.b);
}
我们之前构造的Find对象,_m就是obj。
所以在这里就能看出,是拿vector<my_struct> 中的每一个元素与obj做比较的。

因此这么做是可以实现的。
进一步还可以重载一下my_struct的”==“运算符,以及构造函数

struct my_struct
{

    //里面只有基础类型
    int a;
    int b;
    bool operator==(const my_struct &m1)
    {
        cout<<"call my_struct==\n";
        return a == m1.a && b == m1.b;
    }
    my_struct(const int &A, const int &B) : a(A), b(B) {cout<<"create my_struct instance\n";}
};

Find 的运算符()重载进一步修改为:
bool Find::operator ()(const my_struct& m1)
{
	return _m == m1;
}

以后要想查找自己定义的类/结构体,就可以这样做,自己定义一个查找类Find,里面声明一个成员变量(就是你想要查找的对象类型),并重载 ‘( )’ 运算符,就可以搞定啦!
最后在下面贴上自己测试的代码:

代码样例

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct my_struct
{

    //里面只有基础类型
    int a;
    int b;
    bool operator==(const my_struct &m1)
    {
        cout<<"call my_struct==\n";
        return a == m1.a && b == m1.b;
    }
    my_struct(const int &A, const int &B) : a(A), b(B) {cout<<"create my_struct instance\n";}
};

class Find
{
public:
    Find(my_struct m) : _m(m) { cout << "create Find instance\n"; }
    bool operator()(const my_struct &m1)
    {
        cout<<"call Find()\n";
        return _m == m1;
    }
    my_struct _m;
};

void fun2()
{
    vector<my_struct> v;
    v.push_back(my_struct(1, 2));
    v.push_back(my_struct(2, 3));
    v.push_back(my_struct(4, 5));
    my_struct obj(2, 1);
    auto first = v.begin();
    auto end = v.end();
    auto pos = find_if(first, end, Find(obj));
    //Find o(obj);
    Find o = Find(obj);
    bool b = o(obj);
    cout<<b<<endl;
    if (pos != v.end())
        cout << "find!";
    else
        cout << "not find~";
}

int main()
{
    fun2();
}

运行结果:
在这里插入图片描述

回过头来看我们最开始遇到的问题,是不是就清晰了许多呢?

通过这个例子不仅学习到了如何定义函数在vector中查找自定义类的对象,还对运算符重载的知识加深了了解。

拓展:其实这个运算符重载还可以用到许许多多的方面,比如优先队列priority queue里按照自己的结构体排序,等等,还可以重载运用到sort,count_if等等alogrithm库里面的一些函数。有了这个理解,就可以做到一招鲜吃遍天啦~

更多知识可以学习:仿函数,下面接下来拓展学习,如果我学懂了继续更新下一篇,仿函数篇,把这一条线上遇到的问题都摸透^ ^。

如果能帮助到大家,就非常开心啦!十分感谢大家的支持!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-20 14:54:28  更:2021-08-20 14:54:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 5:21:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计