函数指针是一种在C、C++、其他类 C 语言的指针。
C语言标准规定,函数指示符(function designator,即函数名字)既不是左值,也不是右值。但C++语言标准规定函数指示符属于左值,因此函数指示符转换为函数指针的右值属于左值转换为右值。
函数指针用于做接口的抽象。屏蔽函数实现过程。
最经典的例子就是比两个对象的大小。
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,这个操作会遍历所有的实现类,并以此调用每个类实现的接口。看下伪代码
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传递过去,这样是否可行,能这样写吗?
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
,因此需要将该对象作为显式参数传入。
但是如果非要传入成员函数咋办,因为有时候成员函数会改变类的一些成员变量,不能静态化。
我们可以这样设计:
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可以设计
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 删除。