【STL十五】函数对象:可调用对象
- 一、可调用对象
- 1、定义
- 2、分类
- 二、普通函数
- 1、直接调用普通函数
- 2、函数指针、函数引用
- 三、仿函数——函数对象
- 四、lambda表达式
- 五、类的静态成员函数——(作为可调用对象,没有实用价值)
- 六、类的非静态成员函数——(作为可调用对象,没有实用价值)
- 七、可被转换为函数的类的对象——(作为可调用对象,没有实用价值)
- 简介
1、可调用对象这个概念在哔哩哔哩的一个视频中看到的概念。
2、可调用对象:平时大家会用到的就三个:普通函数、仿函数、lambda表达式。
3、本篇文章的重点在函数指针、函数引用;其它另外三种没有实用价值。
一、可调用对象
1、定义
- 可调用对象:可以像函数一样调用的对象。
- 可调用对象有类型,可以用指针存储它们的地址,可以被引用(类的成员函数除外)
2、分类
- 普通函数
- 仿函数
- lambda函数
- 类的静态成员函数——(作为可调用对象,没有实用价值)
- 类的非静态成员函数——(作为可调用对象,没有实用价值)
- 可被转换为函数的类的对象——(作为可调用对象,没有实用价值)
二、普通函数
1、直接调用普通函数
- 普通函数类型的别名
#include <iostream>
#include<functional>
using namespace std;
using Fun = void(int, const string&); //普通函数类型的别名
Fun show; // 声明普通函数
// 上面2行等价于以下1行
//void show(int, const string&); //声明普通函数
void show(int i, const string& message)
{
cout << "第" << i << "个: " << message;
}
int main()
{
show(1, "可能南方的阳光 照着北方的风"); //直接调用普通函数
}
以下代码是错误的,不能用函数类型定义函数的实体。
//Fun show2(int i, const string& message)
//{
// cout << "第" << i << "个: " << message;
//}
输出
第1个: 可能南方的阳光 照着北方的风
2、函数指针、函数引用
using Fun = void(int, const string&); //普通函数类型的别名
- 用别名可以定义函数指针
Fun* fp1 = show; // 声明函数 指针,指向 普通函数
- 用别名可以定义引用,
我们很少使用函数引用,因为引用的本质是指针,所以他们是一样的。
`Fun& fr1 = show; // 声明函数 引用,引用 普通函数`
- demo
#include <iostream>
#include<functional>
using namespace std;
using Fun = void(int, const string&); //普通函数类型的别名
Fun show; // 声明普通函数
// 上面2行等价于以下1行
//void show(int, const string&); //声明普通函数
void show(int i, const string& message)
{
cout << "第" << i << "个: " << message << endl;
}
int main()
{
// c++风格
Fun* fp1 = show; // 声明函数 指针,指向 普通函数
Fun& fr1 = show; // 声明函数 引用,引用 普通函数
fp1(2, "可能西安城墙上 有人誓言不分"); // 用函数指针调用普通函数
fr1(3, "可能西安城墙上 有人誓言不分"); // 用函数引用调用普通函数
// c语言风格
void(*fp2)(int, const string&) = show; // 声明函数 指针,指向 普通函数
void(&fr2)(int, const string&) = show; // 声明函数 引用,引用 普通函数
fp2(4, "可能要去到大理 才算爱得认真"); // 用函数指针调用普通函数
fr2(5, "可能要去到大理 才算爱得认真"); // 用函数引用调用普通函数
}
输出
第2个: 可能西安城墙上 有人誓言不分
第3个: 可能西安城墙上 有人誓言不分
第4个: 可能要去到大理 才算爱得认真
第5个: 可能要去到大理 才算爱得认真
三、仿函数——函数对象
- 参考:【STL十四】函数对象(function object)_仿函数(functor)——lambda表达式
#include <iostream>
//
using namespace std;
class Print
{
public:
void operator()(const char str[])
{
cout << str << endl;
}
};
int main() {
Print ob;
ob("hello world");
Print()("hello world"); //匿名函数对象
Print& obr = ob; //引用函数
obr("hello world"); //用对象的引用调用仿函数
}
输出
hello world
hello world
hello world
四、lambda表达式
- 参考:【STL十四】函数对象(function object)_仿函数(functor)——lambda表达式
五、类的静态成员函数——(作为可调用对象,没有实用价值)
#include <iostream>
using namespace std;
using Fun = void(int, const string&); // 普通函数类型的别名。
struct AA // 类中有静态成员函数。
{
static void show(int bh, const string& message) {
cout << "第" << bh << "个," << message << endl;
}
};
int main()
{
AA::show(6, " 可能(程响)"); // 直接调用静态成员函数。
Fun* fp1 = AA::show; // 用函数指针指向静态成员函数。
Fun& fr1 = AA::show; // 引用静态成员函数。
fp1(7, " 可能北京的后海 许多漂泊的魂"); // 用函数指针调用静态成员函数。
fr1(8, " 可能北京的后海 许多漂泊的魂"); // 用函数引用调用静态成员函数。
void(*fp2)(int, const string&) = AA::show; // 用函数指针指向静态成员函数。
void(&fr2)(int, const string&) = AA::show; // 引用静态成员函数。
fp2(9, " 可能成都小酒馆 有群孤独的人"); // 用函数指针调用静态成员函数。
fr2(10, "可能北京的后海 许多漂泊的魂"); // 用函数引用调用静态成员函数。
}
输出
第6个, 可能(程响)
第7个, 可能北京的后海 许多漂泊的魂
第8个, 可能北京的后海 许多漂泊的魂
第9个, 可能成都小酒馆 有群孤独的人
第10个,可能北京的后海 许多漂泊的魂
六、类的非静态成员函数——(作为可调用对象,没有实用价值)
类的非静态成员函数= 类的普通成员函数
-
类的非静态成员函数有地址,但是,只能通过类的对象才能调用它,所以,C++对它做了特别处理。
-
类的非静态成员函数只有指针类型,没有引用类型,不能引用。
-
普通成员函数指针 vs 类的成员函数的指针
// 普通成员函数
void( *fp2)(int, const string&) = show; // 声明函数 指针,指向 普通函数
// 类的成员函数
void (CC:: * fp1)(int, const string&) = &CC::show; // 定义类的成员函数的指针。
- 普通函数地址 vs 成员函数地址
// 普通函数地址
= show
= show
// 类的成员函数地址
= &CC::show
- demo
#include <iostream>
using namespace std;
class CC // 类中有普通成员函数。
{
public:
void show(int bh, const string& message) {
cout << "第" << bh << "行 ," << message << endl;
}
};
int main()
{
CC cc;
cc.show(14, "可能(程响)");
using pFun = void (CC::*)(int, const string&); // 类成员函数的指针类型。
pFun fp2 = &CC::show; // 让类成员函数的指针指向类的成员函数的地址。
(cc.*fp2)(15, "可能拥有过梦想 才能叫做青春"); // 用类成员函数的指针调用类的成员函数。
void (CC:: * fp1)(int, const string&) = &CC::show; // 定义类的成员函数的指针。
(cc.*fp1)(16, "可能拥有过梦想 才能叫做青春"); // 用类的成员函数的指针调用成员函数。
}
输出
第14行 ,可能(程响)
第15行 ,可能拥有过梦想 才能叫做青春
第16行 ,可能拥有过梦想 才能叫做青春
七、可被转换为函数的类的对象——(作为可调用对象,没有实用价值)
- 实际开发中,没有意义,不做介绍。
参考
1、C++ STL 容器库 中文文档
2、STL教程:C++ STL快速入门
3、https://www.apiref.com/cpp-zh/cpp/header.html
4、https://en.cppreference.com/w/cpp/container
5、WIKI教程_C ++标准库_C++ Library - <iterator>
6、哔哩哔哩_系统化学习C++_C++11神器之可调用对象包装器和绑定器