函数对象

函数对象

定义

重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象。

class FuncOdject {
public:
    void operator()() {
        cout << "hello c++!" << endl;
    }
}
// 实例化一个对象
FuncOdject val;
val() // cout << "hello c++!" << endl;
// 这有点像使用函数
/*
void val()  
{  
    cout<<"Hello C++!"<<endl;  
}
*/  

使用函数对象的原因

虽然调用函数和使用函数对象有相同的效果,但函数对象有独特的优势,主要体现在STL的使用。

  • 1 . 函数对象可以有自己的状态。我们可以在类中定义状态变量,这样一个函数对象在多次的调用中可以共享这个状态。但是函数调用没这种优势,除非它使用全局变量来保存状态。

  • 2 . 函数对象有自己特有的类型,而普通函数无类型可言。这种特性对于使用C++标准库来说是至关重要的。这样我们在使用STL中的函数时,可以传递相应的类型作为参数来实例化相应的模板,从而实现我们自己定义的规则。比如自定义容器的排序规则。

实例

1. 使用到内部状态的函数对象

// 定义一个函数对象
class SuccessiveNumGen  
{  
public:  
    SuccessiveNumGen(int origin = 0):m_origin(origin){}  
    int operator() ()  
    {  
        return m_origin++;  
    }  
private:  
    int m_origin;  
};

vector<int> dest;
generate_n(back_inserter(dest),10,SuccessiveNumGen(3));  

此处使用generate_n来表示函数自动调用n次。

back_inserter是一个函数适配器,它返回一个函数对象,并且每次都在dest最后存放元素。

这样,最终容器中的内容为 3,4,5,6,……,12。通过使用不同的起始数字来初始化不同的函数对象,可以生成不同的数字序列。

2. 自定义容器set对字符串string的排序规则

class StringSort {
public:
    bool operator() (const string &str1, const string &str2) const
    {
        return str1 > str2;
    }
};
int main() {
    set<string,StringSort> myset;
    myset.insert("A");
    myset.insert("B");
    cout << *myset.begin() << endl;
    return 0;
}

3. 谓词函数(predicate)

class NoLess
{
public:
    NoLess(int min = 0):m_min(min){}
    bool operator() (int value) const
    {
        return value >= m_min;
    }
private:
    int m_min;
};
int main() {
    vector<int> myvec;
    myvec.push_back(1);
    myvec.push_back(2);
    myvec.push_back(10);
    remove_if(myvec.begin(), myvec.end(), NoLess(3));
    return 0;
}

find_if,remove_if都需要一个谓词函数来实现。而这种函数最好用函数对象来实现。(如果尝试调用函数来实现,会出现错误。而且并不好用,因为每次都要重新改写函数的代码来改变判断的条件。)

意外情况:

有一点需要指出的是,在调用用到函数对象的标准库算法时,除非显式地指定模板类型为“传引用”,否则默认情况下函数对象是“按值传递”的!因此,如果传递的是一个具有内部状态的函数对象,则被改变状态的是函数内部被复制的临时对象,函数结束后随之消失。真正传进来的函数对象状态并为改变。 
测试如下:

class Nth  
{  
public:  
    Nth(int n=0):m_nth(n),m_count(1){}  
    bool operator() (int)  
    {  
        return m_count++ == m_nth;  
    }  

    int GetCount()const  
    {  
        return m_count;  
    }  

private:  
    int m_nth;  
    int m_count;  
};  

Nth nth(3);  
vector<int>::iterator nthItr = find_if(dest.begin(),dest.end(),nth);  
//dest内容为连续数字:3,4,5,6,……,12  
cout<<"3rd:"<<*nthItr<<endl;  
cout<<"State:"<<nth.GetCount()<<endl;  
// 输出结果为,确实能找到第三个数字(5)。
// 但查看nth的状态时,返回的m_count依然为0。说明nth确实未被修改。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值