前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >日更系列:使用函数指针的小伎俩

日更系列:使用函数指针的小伎俩

原创
作者头像
mariolu
发布2021-10-21 00:29:33
6960
发布2021-10-21 00:29:33
举报

一、什么是函数指针

函数指针是一种在C、C++、其他类 C 语言的指针。

C语言标准规定,函数指示符(function designator,即函数名字)既不是左值,也不是右值。但C++语言标准规定函数指示符属于左值,因此函数指示符转换为函数指针的右值属于左值转换为右值。

二、函数指针应用

函数指针用于做接口的抽象。屏蔽函数实现过程。

最经典的例子就是比两个对象的大小。

代码语言:javascript
复制
typedef (bool)(*CompareFuncT) (struct Object, struct Object);
struct Object&
select(struct Object A, struct Object B, CompareFuncT compare) {
    if (compare(A, B)) return A;
    else return B;
}

这里可以传入各种比较函数,只要是遵循CompareFuncT接口的函数即可。

这个接口函数可以是普通函数,类的静态函数,类的成员函数可以吗?

三、使用类的成员函数作为函数指针可以吗

再来看一个例子:

我们有1个接口类,和个实现接口类的实现类。

然后呢,我们对他操作manipulate,这个操作会遍历所有的实现类,并以此调用每个类实现的接口。看下伪代码

代码语言:javascript
复制
class TrancatedCalculator {
    virtual bool IsTrancated(std::shared_ptr<Context>&, Item&){};
}
class FilterActiveApp : public TrancatedCalculator {
    bool IsTrancated(std::shared_ptr<ScheduleRankContext>&, Item&) override;
}

void do() {
    std::vector<std::unique_ptr<TrancatedCalculator>> truncated_calculator_vec;
    for (auto& calculator: truncated_calculator_vec) {
        truncated_calculator_vec->IsTruncated(item);
    }
}

好了,这里我们继续扩张do的逻辑,然后我认为需要遵守函数的单一指责原则。然后在do里面另分出一个truncate函数,然后把truncated_calculator_vec->IsTrancated传递过去,这样是否可行,能这样写吗?

代码语言:javascript
复制
void foo(IsTruncatedFuncT fn, Item item) {return;}

void do(){
    std::vector<std::unique_ptr<TrancatedCalculator>> truncated_calculator_vec;
    for(auto& calculator: truncated_calculator_vec){
        //truncated_calculator_vec->IsTruncated(item);
        foo(truncated_calculator_vec->IsTruncated, item);//可以这样写吗?答案是不可以
    }
}

显然不能这样写,

在这里需要解释一个问题是“成员指针”而不是普通的函数指针。

函数的成员指针不仅仅是函数指针。在实现方面,编译器不能使用简单的函数地址,因为你不知道要调用的地址(想想虚函数)。当然,还需要知道对象才能提供this隐式参数。

如果要提供指向现有代码的函数指针,应该编写类的静态成员函数。静态成员函数不需要this,因此需要将该对象作为显式参数传入。

但是如果非要传入成员函数咋办,因为有时候成员函数会改变类的一些成员变量,不能静态化。

我们可以这样设计:

代码语言:javascript
复制
 bool
 has_truncated(std::unique_ptr<TrancatedCalculator>& tc,  std::shared_ptr<Context>& ctx, Item& item) {
     return tc->IsTrancated(ctx, item);
 }

然后我们传入的除了has_truncated函数指针外,还需要传入std::unique_ptr<TrancatedCalculator>&对象。 然后我们这里的foo可以设计

代码语言:javascript
复制
 void foo(IsTruncatedFuncT fn, std::shared_ptr<Context>& ctx,
         std::unique_ptr<TrancatedCalculator>& tc, Item& item) {
     fn(tc, ctx, item);
 }

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、什么是函数指针
  • 二、函数指针应用
  • 三、使用类的成员函数作为函数指针可以吗
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档