文章目录
- 可调用对象
- 普通函数
- 类的静态成员函数
- 仿函数
- lambda函数
- 类的非静态成员函数 最重要的
- 可被转换为函数指针的类对象
- 包装器 function
- 适配器bind
- 可变函数和参数实现
- 回调函数实现
- 替代虚函数
可调用对象
在C++中,可以像函数一样调用的有:
普通函数、类的静态成员函数、仿函数、lambda 函数、类的成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。
可调用对象有类型,可以用指针存储他们的地址,可以被引用
普通函数
普通函数类型可以声明函数、定义函数指针和函数引用,但是,不能定义函数的实体
#include<iostream>
#include<string>
using namespace std;using Fun = void(int,const string&);
Fun show;//声明普通函数show 不能用函数类型定义函数void show(int x,const string&s){cout<< x <<"--"<< s <<endl;
}
int main(){show(1,"我是一个鸟");void (*f1)(int,const string&) = show;//函数指针指向函数void (&f2)(int,const string&) = show;//函数引用指向函数f1(2,"hello");f2(3,"world");Fun *f3 = show;//函数指针指向函数Fun &f4 = show;//函数引用指向函数f3(4,"hello");f4(5,"world");return 0;
}
类的静态成员函数
类的静态成员函数和普通函数本质上是一样的,把普通函数放在类中而已
#include<iostream>
#include<string>
using namespace std;using Fun = void(int,const string&);
Fun show;//声明普通函数show 不能用函数类型定义函数
struct AA{static void show(int x,const string&s){cout<< x <<"--"<< s <<endl;}
};int main(){AA::show(1,"我是一个鸟");void (*f1)(int,const string&) = AA::show;//函数指针指向函数void (&f2)(int,const string&) = AA::show;//函数引用指向函数f1(2,"hello");f2(3,"world");Fun *f3 = AA::show;//函数指针指向函数Fun &f4 = AA::show;//函数引用指向函数f3(4,"hello");f4(5,"world");return 0;
}
仿函数
本质是类
class TT{
public:void operator()(int b,const string&s){cout<< b<<"=="<<s <<endl;}
};int main() {TT t;t(0,"dad");//对象调用TT()(1,"dasd");//匿名对象调用仿函数TT&t0 = t;t0(2,"dy");//对象的引用调用return 0;
}
lambda函数
本质是仿函数
auto fd = [](int x,const string&s){cout<< x<<"=="<<s<<endl;
};
int main() {fd(1,"du");auto &ff = fd;ff(2,"yxx");
}
类的非静态成员函数 最重要的
只有指针类型,没有引用类型
class CC{
public:void show(int b,const string&s){cout<< b<<"=="<<s <<endl;}
};
int main() {CC c;c.show(1,"dxx");//定义类的成员函数指针Cvoid (CC::*f1)(int,const string&) = &CC::show;(c.*f1)(2,"nihao");//定义类的成员函数指针C++using Fun = void(CC::*)(int,const string&);Fun f2 = &CC::show;(c.*f2)(3,"xxxxx");
}
可被转换为函数指针的类对象
类可以重载类型转换运算符 operator 数据类型()
如果数据类型
是函数指针或函数引用,那么该类的实例也将成为可调用对象
本质是类 调用的代码像函数
实际开发意义不大
void show(int x){cout<< x <<endl;
}
class CC{
public:using F = void(*)(int);operator F(){return show;//返回普通函数//只能返回普通全局函数和类的静态成员函数}
};
int main() {CC c;c(10);
}
包装器 function
包含头文件 functional
#include<iostream>
#include<functional>
#include<string>
using namespace std;//普通函数
void show(int x, const string& s) {cout << "你好" << x << "==" << s << endl;
}//类内有静态成员函数
struct AA{static void show(int x, const string& s) {cout << "你好" << x << "==" << s << endl;}
};//仿函数
struct BB{void operator()(int x, const string& s) {cout << "你好" << x << "==" << s << endl;}
};//lambda函数
auto f = [](int x, const string& s) {cout << "你好" << x << "==" << s << endl;};//类内有普通成员函数
struct CC{void show(int x, const string& s) {cout << "你好" << x << "==" << s << endl;}
};//可被转换为函数指针的类
struct DD {using Fun = void(*)(int, const string&);operator Fun() {return show;}
};int main() {//普通函数//<函数返回类型(参数列表)>function<void(int, const string&)>fn1 = show;//包装普通全局函数showfn1(1, "function包装器对全局函数");//类内有静态成员函数function<void(int, const string&)>fn2 = AA::show;//包装普通全局函数showfn2(2, "function包装器对类内静态成员函数");//仿函数function<void(int, const string&)> fn3= BB();fn3(3, "function包装器对仿函数");//lambda函数function<void(int, const string&)> fn4 = f;fn4(4, "function包装器对lambda");//类内普通函数CC c;function<void(CC&c,int, const string&)>fn5 = &CC::show;fn5(c, 5, "function包装器对类内普通函数");//可被转换为函数指针的类DD d;function<void(int, const string&)>fn6 = d;fn6(6, "function包装器对可被转换为函数指针的类");return 0;
}
注意:
- 重载了
bool
运算符,用于判断是否包装了可调用对象 - 如果std::function对象未包装可调用对象,使用std::function对象将抛出std::bad_function_call异常
适配器bind
std::bind()
模板函数是一个通用的函数适配器(绑定器),它用一个可调用对象及其参数,生成一个新的可调用对象,以适应模板
#include<iostream>
#include<functional>
#include<string>using namespace std;void show(int x, const string &s) {cout << x << "--" << s << endl;
}struct AA {void show(int x) {cout << x << endl;}
};int main() {function<void(int, const string &)> f1 = show;f1(1, "按照顺序");// placeholders::_n <>中的第n个和其所在位置的绑定// 传参的顺序按照 <> 的顺序function<void(const string &, int)> f2 = bind(show, placeholders::_2, placeholders::_1);f2("不按照顺序", 2);int x{5};// 绑定的时候默认是x值传递,要是引用要使用ref(x)function<void(const string &)> f3 = bind(show, ref(x), placeholders::_1);x = 500;f3("缺省");function<void(int, const string &, int)> f4 = bind(show, placeholders::_1, placeholders::_2);f4(4, "多参数", 111);//类的非静态成员函数AA a;function<void(int)> f5 = bind(&AA::show, &a, placeholders::_1);f5(45);return 0;
}
可变函数和参数实现
#include<iostream>
#include<functional>using namespace std;void print() {}template<typename T, typename ...Args>
void print(T arg, Args...args) {cout << arg << endl;print(args...);
}template<typename ...Args>
void biaobai(Args...arg) {print(arg...);
}
//万能表白函数
/*** @tparam Fn 可调用函数* @tparam Args 可变参数* @return bind(fn, args...)** 如果传递的值是右值 移动赋值,&&和forward完美转发*/
template<typename Fn, typename ...Args>
auto show_love(Fn fn, Args...args)-> decltype(bind(fn, args...)) {auto f = bind(fn, args...);f();return f;
}void show0(const string &s) {cout << "亲爱的" << s << ",爱你" << endl;
}
void show1(){cout << "亲爱的"<< ",爱你" << endl;
}
auto f = [](const string&s){cout << "亲爱的" << s << ",爱你" << endl;
};struct AA{void operator()(const string &s) {cout << "亲爱的" << s << ",爱你" << endl;}
};int main() {show_love(show0,"ying");show_love(show1);show_love(AA(),"ying");return 0;
}
回调函数实现
在消息队列和网络库的框架中,当接收到消息(报文)时,回调用户自定义的函数对象,把消息(报文)参数传给它,由它决定如何处理
#include<iostream>
#include<functional>using namespace std;template<typename CallBackType>
void performCallback(const string &s, const CallBackType &callback) {callback(s);// 调用回调函数并传递消息
}class MyCallBack {
public:void myFunc(const string &message) {cout << "我的信息是:" << message << endl;}
};int main() {MyCallBack m;auto boundFunc = bind(&MyCallBack::myFunc,&m,placeholders::_1);performCallback("你好啊",boundFunc);return 0;
}
替代虚函数
C++虚函数在执行过程中会跳转两次(先查找对象的函数表,再次通过该函数表中的地址找到真正的执行地址),这样的话,CPU会跳转两次,而普通函数只跳转一次
CPU 每跳转一次,预取指令要作废很多,所以效率会很低(百度)
为了管理的方便 (基类指针可指向派生类对象和自动析构派生类) 保留类之间的继承关系。
包装器和绑定器可以代替虚函数的功能并且无性能损失
#include<iostream>
#include<functional>using namespace std;struct Hero {/*virtual void show(){cout<< "英雄释放了技能" <<endl;}*/function<void()> m_callback; // 用于绑定子类的成员函数//注册子类成员函数,子类成员函数没有参数template<class Fn, class ...Args>void callback(Fn &&fn, Args &&...args) {m_callback = bind(forward<Fn>(fn), forward<Args>(args)...);}//调用子类的成员函数void show() {m_callback();}
};struct XS : public Hero {void show() {cout << "西施释放了技能" << endl;}
};struct HX : public Hero {void show() {cout << "韩信释放了技能" << endl;}
};int main() {int id;cout << "请输入英雄id:";cin >> id;Hero *p = nullptr;if (id == 1) {p = new XS;p->callback(&XS::show, static_cast<XS *>(p));} else if (id == 2) {p = new HX;p->callback(&HX::show, static_cast<HX *>(p));}if (p != nullptr) {p->show();delete p;}return 0;
}