王清欢Randy 王清欢Randy
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
  • C语言基础

    • 数据类型
    • 指针与字符串
    • 结构类型
    • 链表
    • 程序结构
    • 文件
  • C++面向对象编程

    • C++面向对象

      • 从 C 到 C++
      • C++ 类和对象基础
      • C++ 构造函数与析构函数
      • C++ 类和对象提高
      • 运算符重载
      • C++ 继承
      • C++ 多态
    • C++ STL

      • C++ 输入输出流
      • C++ 泛型编程
      • C++ string类
      • C++ 标准模板库 STL 概述
      • C++ 标准模板库 STL 顺序容器
      • C++ 标准模板库 STL 函数对象
        • 函数对象的基本概念
        • 函数对象的实际应用
        • 函数对象的应用示例
        • STL 中的函数对象类模板
          • Greater 函数对象类模板
          • STL 中的大小关系
      • C++ 标准模板库 STL 关联容器
      • C++ 标准模板库 STL 容器适配器
    • C++ 新特性

      • C++11 新特性
  • C&Cpp学习笔记
  • C++面向对象编程
  • C++ STL
王清欢
2023-11-18
目录

C++ 标准模板库 STL 函数对象

# 函数对象

# 函数对象的基本概念

函数对象:如果一个类重载了运算符(),及重载了括号运算符的类,其产生的对象都将成为函数对象。函数对象是个对象,但是用起来看上去像函数调用,实际上也执行了函数调用。

// 函数对象类
class CMyAverage{
public:
    double operator() (int a, int b, int c){
        return (double)(a+b+c)/3;
    }
};

int main(){
    CMyAverage average; // 函数对象
    cout<<average(3,2,3); // 等价与 average.operator()(3,2,3)
    return 0;
}

# 函数对象的实际应用

例如C++中的accumulate的实现源码如下:

template<typename _InputIterator, typename _Tp, typename _BinaryOperation>
_Tp accumulate(_InputIterator _first, _InputIterator _last, _Tp init, _BinaryOperation _binary_op){
    for(;_first != _last; ++_first){
        _init = _binary_op(_init, *_first); // 传入的实参可以是函数或者函数对象
    }
    return _init;
}

在调用accumulate时,和_binary_op形参对应的实参可以是函数或者函数对象

值得注意的是在定义模板template时,使用关键字typename, class并没有什么不同,但是他们又有细微的差别,具体请参考template关键字typename和class的区别,以及模板默认参数 (opens new window)

# 函数对象的应用示例

//累加平方值
int sumSquares(int total, int value){
    return total + value*value;
}
// 输出区间[first,last)中的所有元素
template <typename T>
void printInterval(T first, T last){
    for(;first!=last;++first){
        cout << *first<<" ";
    }
    cout << endl;
}
// 类模板,计算power次方并累加
template <typename T>
class SumPowers{
private:
    int power;
public:
    SumPowers(int p):power(p){}
    const T operator()(const T& total, const T& value){
        T v = value;
        for(int i=0;i<power-1;++i){
            v = v*value;
        }
        return total+v;
    }
};
// 调用示例
int main(){
    vector<int> v{1,2,3,4,5,6,7,8,9,10};
    cout<<"1)";printInterval(v.begin(),v.end()); // 输出v的所有元素
    int result = accumulate(v.begin(),v.end(),0,sumSquares); // 使用sumSquares求平方和
    cout<<"2)"<<result<<endl;
    result = accumulate(v.begin(),v.end(),0,SumPowers<int>(3)); // SumPowers<int> 是由类模板构造的整型模板类,该模板类由实例化了函数对象SumPowers<int>(3),来求立方和
    cout<<"3)"<<result<<endl;
    result = accumulate(v.begin(),v.end(),0,SumPowers<int>(4));
    cout<<"4)"<<result<<endl;
    return 0;
}

上述示例中的函数调用实例化过程:

  1. 求平方和实例化:可以使用函数指针指向函数
int result = accumulate(v.begin(),v.end(),0,sumSquares); // 使用sumSquares求平方和
// 实例化出
int accumulate(vector<int>::iterator first,vector<int>::iterator last,int init,int ( * op)( int,int)) // 用函数指针指向函数
{
    for ( ; first != last; ++first){
    	init = op(init, *first);
    }
    return init;
}
  1. 求立方和实例化:直接使用函数对象指向函数,这样使用面向对象的思想,不用重复编写求次方和的函数
result = accumulate(v.begin(),v.end(),0,SumPowers<int>(3));
// 实例化出
int accumulate(vector<int>::iterator first, vector<int>::iterator last, int init, SumPowers<int> op) // 实例化为函数对象
{
    for ( ; first != last; ++first)
    {
        init = op(init, *first);
    }
    return init;
}

# STL 中的函数对象类模板

​ STL 中由很多类模板可以用来生成函数对象,例如:euqal_to, greater, less等,他们都包含在#include<functional>头文件中。

# Greater 函数对象类模板

​ greater函数对象类模板源码

template<class T>
struct greater : public binary_function<T, T, bool> {
	bool operator()(const T& x, const T& y) const {
		return x > y; //数值大的元素反而小
	}
};

​ greater函数对象的一个典型应用是在双向队列list的sort成员函数,因为list元素顺序的特殊性不能直接使用 STL 算法提供的sort函数

  • 不带参数的sort函数 void sort():将 list 中的元素按 < 运算符规定的比较方法升序排列

  • 带函数对象参数的sort函数

    template <typename T>
    void sort(T op);
    

    ​ 将 list 中的元素按 op 规定的比较方法升序排列,即要比较 x,y 的大小时,看 op(x,y)的返回值,如果返回值为 true 则认为 x小于y,所以 x 应该排在前面

#include <list>
#include <iostream>
#include <iterator>
using namespace std;
class myLess {
public:
    bool operator()(const int & c1, const int & c2){
    	return (c1 % 10) < (c2 % 10); // 个位数较小的元素整体较小
    }
};

template <typename T>
void myPrint(T first, T last){
    for(;first!=last;++first){
        cout<<*first<<",";
    }
}

int main()
{
    const int SIZE = 5;
    int a[SIZE] = {5,21,14,2,3};
    list<int> lst(a,a+SIZE);
    lst.sort(myLess()); // 使用函数对象myLess进行排序
    myPrint(lst.begin(),lst.end());
    lst.sort(greater<int>()); // 使用greater<int>()函数对象进行排序 数值大的元素反而小
    //本句进行降序排序
    myPrint(lst.begin(),lst.end());
    cout<<endl;
    return 0;
}

# STL 中的大小关系

​ 关联容器和STL中许多算法,都是可以自定义比较器的; 在自定义了比较器op的情况下,以下三种说法是等价的:

  • x 小于 y
  • op(x,y) 返回值为 true
  • y 大于 x

自定义大小关系示例如下:

// 函数对象类
class myLess {
public:
    bool operator()(const int & c1, const int & c2){
    	return (c1 % 10) < (c2 % 10); // 个位数较小的元素整体较小
    }
};

// 函数调用
bool myCompare(const int & c1, const int & c2){
    	return (c1 % 10) > (c2 % 10); // 个位数较小的元素整体较小
}

// 模板类
template <class T, class Pred>
T MyMax( T* p, int n, Pred op)
{
    T tmpmax = p[0];
    for( int i = 1;i < n;i ++ ){
        if(op(tmpmax,p[i]))
        	tmpmax = p[i];
    } 
    return tmpmax;
};

int main()
{
    int a[] = {35,7,13,19,12};
    cout << MyMax(a,5,MyLess()) << endl; // 自定义函数对象大小比较
    cout << MyMax(a,5,MyCompare) << endl; // 自定义函数大小比较
    return 0;
}
上次更新: 2023/11/19, 12:55:48
C++ 标准模板库 STL 顺序容器
C++ 标准模板库 STL 关联容器

← C++ 标准模板库 STL 顺序容器 C++ 标准模板库 STL 关联容器→

Theme by Vdoing | Copyright © 2023-2024 Wang Qinghuan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式