在C++中,可以像函数一样调用的有:
普通函数、类的静态成员函数、仿函数、lambda 函数、类的成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。
可调用对象有类型,可以用指针存储他们的地址,可以被引用
普通函数类型可以声明函数、定义函数指针和函数引用,但是,不能定义函数的实体
#include
#include
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
#include
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;
}
本质是仿函数
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");
//定义类的成员函数指针C
void (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);
}
包含头文件 functional
#include
#include
#include
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;//包装普通全局函数show
fn1(1, "function包装器对全局函数");
//类内有静态成员函数
function<void(int, const string&)>fn2 = AA::show;//包装普通全局函数show
fn2(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::bind()
模板函数是一个通用的函数适配器(绑定器),它用一个可调用对象及其参数,生成一个新的可调用对象,以适应模板
#include
#include
#include
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
#include
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
#include
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
#include
using namespace std;
struct Hero {
/*virtual void show(){
cout<< "英雄释放了技能" <
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;
}