可调用对象用处⼴泛:
- ⽐如在使⽤⼀些基于范围的模板函数时,如 sort(It first, It last, Compare cmp)、all_of()、find_if() 等),需要传⼊⼀个可调⽤对象客制化处理。
- 在处理⼀些回调函数、触发函数时,也会使⽤可调⽤对象。
满足以下条件的为可调用对象:
- 是一个函数或类成员函数
- 是一个函数指针
- 是一个重载operator()的类对象
- lambda表达式
- 是一个可转型为函数指针的类对象
- 是一个类成员函数指针
- bind表达式、std::function()
- 协程
普通函数
- int add(int a, int b) {
- return a + b;
- }
- int main() {
- int num1, num2;
- std::cout << "Enter two numbers: ";
- std::cin >> num1 >> num2;
- int sum = add(num1, num2);
- std::cout << "The sum of " << num1 << " and " << num2 << " is: " << sum << s << "\n";
- return 0;
- }
复制代码 类成员函数
- #include <iostream>
- using namespace std;
- class Box{
- public:
- double length; // ⻓度
- double breadth; // 宽度
- double height; // ⾼度
- // 成员函数声明
- double getVolume(void);
- void setLength( double len );
- void setBreadth( double bre );
- void setHeight( double hei );
- };
- // 成员函数定义
- double Box::getVolume(void)
- {
- return length * breadth * height;
- }
- void Box::setLength( double len )
- {
- length = len;
- }
- void Box::setBreadth( double bre )
- {
- breadth = bre;
- }
- void Box::setHeight( double hei )
- {
- height = hei;
- }
- int main( )
- {
- Box box; // 声明 box,类型为 Box
- double volume = 0.0; // ⽤于存储体积
- // 详述
- box.setLength(6.0);
- box.setBreadth(7.0);
- box.setHeight(5.0);
- // 体积
- volume = box.getVolume();
- cout << "box 的体积:" << volume <<endl;
- return 0;
- }
复制代码 类静态成员函数
类中的静态成员函数作⽤在整个类的内部,类静态成员函数属于类而非对象。静态成员函数只能访问对应类内部的静态数据成员(由于静态成员函数没有this指针)。类的static函数在类内声明、类外界说时,类内利用static修饰,类外则不能加static关键字,否则会出现编译错误。
- class Box{
- private:
- int _non_static;
- static int _static;
- public:
- int a(){
- return _non_static;
- }
- static int b(){
- //_non_static=0; 错误
- //静态成员函数不能访问⾮静态成员变量
- return _static;
- }
- static int f(){
- //a(); (不对,静态成员函数不能访问⾮静态成员函数)
- return b();
- }
- };
- int Box::_static= 0;// static静态成员变量可以在类的外部修改
- int main(){
- Box box;
- Box* pointer=&box;
- box.a();
- pointer->a();
- Box::b(); // 类名::静态成员函数名
- return 0;
- }
复制代码 与类成员函数的区别
- 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
- 普通成员函数有 this 指针,可以访问类中的任意成员;⽽静态成员函数没有 this 指针。
仿函数
仿函数就是重载了()运算符的类对象,函数功能通过重载()实现。(⾏为雷同函数,故称仿函数)。实际上就是创建⼀个类,该类重载了()运算符,使得类的实例可以像函数⼀样被调⽤。这允许你在函数对象内部生存状态,并在调⽤时执⾏操作。
简单示例
- class Foo
- {
- void operator()()
- {
- cout << __FUNCTION__ << endl;
- }
- };
- int main()
- {
- Foo a;
- //定义对象调⽤
- a.operator()();
- //直接通过对象调⽤
- a();
- //通过临时对象调⽤
- Foo()();
- }
复制代码 高级用法-状态保持
仿函数可以具有成员变量,因此在多次调用之间可以保持状态。这在算法需要记载或更新某些值的情况下非常有效。
思量一个例子:对一个vector统计长度小于5的string的个数
优缺点
优点
- 状态保持:仿函数可以具有成员变量,因此在多次调用之间可以保持状态。
- 更机动的接口设计:仿函数可以根据需要定制接口,以适应特定的算法或场景。比方,可以根据算法需要添加额外的成员函数或数据成员。
- 更好的封装:仿函数可以将数据和操作封装在一个单独的对象中,这有助于实现更清晰、更模块化的代码。
- 缺点
- 需要单独实现一个类
函数指针
与数据项相似,函数也有所在。函数的所在就是存储它的机器语⾔代码内存的开始所在。通常情况下,这些所在对⽤⼾⽽⾔并不重要,但对于步伐⽽⾔,却很有⽤。⽐⽅说,可以编写将另⼀个函数的所在作为参数的函数,这样第⼀个函数就可以或许找到第⼆个函数,并运⾏它。与直接调⽤另⼀个函数相⽐,这种⽅法虽然很笨拙,但是它允许在不同的时间传递不同函数的所在,这也就意味着可以在不同的时间使⽤不同的函数。
获取函数所在
函数名,不加()
声明并调用函数指针
利用using而非old style声明函数指针!
留意两种方式绑定函数的区别!
- #include<iostream>
- int add(int a, int b) {
- return a + b;
- }
- int main() {
- // 使用 using 声明函数指针类型
- using AddFunctionPtr = int (*)(int, int);
- // 创建函数指针变量并指向 add 函数
- AddFunctionPtr my_add_function = &add;
- // 使用函数指针调用 add 函数
- int result = my_add_function(3, 4);
- return 0;
- }
复制代码- #include<iostream>
- int add(int a, int b) {
- return a + b;
- }
- int main() {
- // 使用 old style 声明函数指针
- int (*my_add_function )(int, int);
- // 指向 add 函数
- my_add_function = &add;
- // 使用函数指针调用 add 函数
- int result = my_add_function(3, 4);
- // int result = (*my_add_function)(3, 4); // ok
- return 0;
- }
复制代码 lambda表达式
Lambda表达式是Modern C++的⼀个语法糖 。 Lambda表达式用于构造闭包:可以或许捕获作用域中的变量的无名函数对象。
语法界说
- 没有显式模板形参的 lambda 表达式(可以不泛型)
- [捕获列表] [前属性] [形参列表] [说明符] [异常] [后属性] [返回类型] [约束] [函数体]
- [capture list] front-attr(opt) (params) specs(opt) exception(opt) back-attr(opt) railing-type(opt) requires(opt) {body}
复制代码
- 有显式模板形参的 lambda 表达式(必然泛型)(C++20起)
捕获
捕获 是一个含有>=0个捕获符 的逗号分隔列表,可以默认捕获符 开始。捕获列表界说了可以从 lambda 函数体之内访问的外部变量。默认捕获符只有&(按引用) 和 =(按复制),它们都将隐式捕获被利用的自动存储期变量(函数能看到的任一变量)。
留意:以默认捕获符隐式捕获的当前对象(*this),将始终按引用捕获,纵然默认捕获符是 =。
单个捕获符
- 简单的按复制捕获
- 作为包展开的简单的按复制捕获
- 带初始化器的按复制捕获
- 简单的按引用捕获
- 作为包展开的简单的按引用捕获
- 带初始化器的按引用捕获
- 当前对象的简单的按引用捕获
- 当前对象的简单的按复制捕获
- 初始化器为包展开的按复制捕获
- 初始化器为包展开的按引用捕获
- 不可重复捕获
- 当默认捕获符是 & 时,后继的简单捕获符不能以 & 开始
- struct S2 { void f(int i); };
- void S2::f(int i)
- {
- [&]{}; // OK:默认按引用捕获
- [&, i]{}; // OK:按引用捕获,但 i 按值捕获
- [&, &i] {}; // 错误:按引用捕获为默认时的按引用捕获
- [&, this] {}; // OK:等价于 [&]
- [&, this, i]{}; // OK:等价于 [&, i]
- }
复制代码 - 当默认捕获符是 = 时,后继的简单捕获符必须以 &、*this (C++17 起)、this (C++20 起) 之一开始。
- struct S2 { void f(int i); };
- void S2::f(int i)
- {
- [=]{}; // OK:默认按复制捕获
- [=, &i]{}; // OK:按复制捕获,但 i 按引用捕获
- [=, *this]{}; // C++17 前:错误:无效语法
- // C++17 起:OK:按复制捕获外围的 S2
- [=, this] {}; // C++20 前:错误:= 为默认时的 this
- // C++20 起:OK:同 [=]
- }
复制代码 - 任何捕获符只可以出现一次,而且名字不能与任何形参名雷同:
- struct S2 { void f(int i); };
- void S2::f(int i)
- {
- [i, i] {}; // 错误:i 重复
- [this, *this] {}; // 错误:"this" 重复(C++17)
-
- [i] (int i) {}; // 错误:形参和捕获的名字相同
- }
复制代码
std::function()
协程
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |