四大类“函数“

发布于:2024-07-05 ⋅ 阅读:(16) ⋅ 点赞:(0)

函数的定义:能够完成某个功能的一段代码——叫函数

一、函数(函数指针)

1.从C语言开始讲函数,可以很负责任的告诉大家啊:C生万物;接下来,我们一起将见证花里胡哨的C语言\C++函数;

#include<iostream>
using namespace std;

typedef void* (*ptr0)(void* b);//定义了一个函数类型指针

struct parameter   
{
    int a = 1;
    int b = 2;
};
void* ptr1(void* a)
{
    cout << a << endl;
    return nullptr;
}
void* ptr3(void* b)  //ptr3和ptr4,都属于上面定义的这个函数指针类型;
{
    ((ptr0)b)((void*)10);
    return nullptr;
}
void* ptr4(void* a) //参数不止可以传内置类型(int\char等,还可以传结构体,函数指针)
{
    parameter* ptr = (parameter*)a;
    cout << ptr->a << endl;
    cout << ptr->b << endl;
    return nullptr;
}

int main()
{
    parameter s;
    parameter *ptr = &s;
    ptr4((void*)ptr);  //传结构体

    int a = 10;
    ptr3((void*)ptr1);//传变量或函数指针;
    return 0;
}

 传参数,哪怕是C语言的参数包,C++的可变参数包(我没有看过C++或C语言的源代码),应该大多可能都是由类似的地址加偏移量,或是上述这种传结构体形式构成,肯定各有优缺点;但肯定是越靠近本质,玩的越花。

二、仿函数

1.正常情况下,一个类的设计,肯定是关联性越低越好,调用函数使用的是函数指针,调用一个函数使用一个函数指针;调用10个使用10个函数指针;当然也可以采用讲解一中的方法,把函数指针改成指针数组,一次性的传进去;

2.C++不再使用上述方法,而是把函数包装成类的函数重载的方式,使看上去和函数一摸一样,所以叫仿函数

#include<iostream>
using namespace std;

class A
{
public:
    int operator()(int a = 10, int b = 20)
    {
        return a > b ? a : b;
    }
};

int main()
{
    A a;
    int c = A(10,20);
    cout << c << endl;
    return 0;
}

三、Lambda

Lambda 表达式书写格式: [capture-list] (parameters) mutable -> return-type { statement
}
1. lambda 表达式各部分说明
[capture-list] : 捕捉列表 ,该列表总是出现在 lambda 函数的开始位置, 编译器根据 []
判断接下来的代码是否为 lambda 函数 捕捉列表能够捕捉上下文中的变量供 lambda
函数使用
(parameters) :参数列表。与 普通函数的参数列表一致 ,如果不需要参数传递,则可以
连同 () 一起省略
mutable :默认情况下, lambda 函数总是一个 const 函数, mutable 可以取消其常量
性。使用该修饰符时,参数列表不可省略 ( 即使参数为空 )
->returntype :返回值类型 。用 追踪返回类型形式声明函数的返回值类型 ,没有返回
值时此部分可省略。 返回值类型明确情况下,也可省略,由编译器对返回类型进行推
{statement} :函数体 。在该函数体内,除了可以使用其参数外,还可以使用所有捕获
到的变量。
注意: 在lambda 函数定义中, 参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为
。因此 C++11 最简单的 lambda 函数为: []{} ; lambda 函数不能做任何事情。
2. 捕获列表说明
捕捉列表描述了上下文中那些数据可以被 lambda 使用 ,以及 使用的方式传值还是传引用
[var] :表示值传递方式捕捉变量 var
[=] :表示值传递方式捕获所有父作用域中的变量 ( 包括 this)
[&var] :表示引用传递捕捉变量 var
[&] :表示引用传递捕捉所有父作用域中的变量 ( 包括 this)
[this] :表示值传递方式捕捉当前的 this 指针
注意:
a. 父作用域指包含 lambda 函数的语句块
b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割
比如: [=, &a, &b] :以引用传递的方式捕捉变量 a b ,值传递方式捕捉其他所有变量
[& a, this] :值传递方式捕捉变量 a this ,引用方式捕捉其他变量
c. 捕捉列表不允许变量重复传递,否则就会导致编译错误
比如: [=, a] = 已经以值传递方式捕捉了所有变量,捕捉 a 重复
i d. 在块作用域以外的 lambda 函数捕捉列表必须为空
e. 在块作用域中的 lambda 函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者
非局部变量都
会导致编译报错。
f. lambda 表达式之间不能相互赋值 ,即使看起来类型相同
  // 复制捕捉 x,且各部分都很完善;
    int x = 10 ;
    auto add_x = [ x ]( int a ) mutable->int { x *= 2 ; return a + x ; };
    cout << add_x ( 10 ) << endl ;

四、function包装器

解释:function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。

std::function 在头文件 < functional >
// 类模板原型如下
template < class T > function ;     // undefined
template < class Ret , class ... Args >
class function < Ret ( Args ...) > ;
模板参数说明:
Ret : 被调用函数的返回类型
Args… :被调用函数的形参
这个玩的更花!!

#include<iostream>
using namespace std;

#include <functional>
int f(int a, int b)
{
    return a + b;
}
struct Functor
{
public:
    int operator() (int a, int b)
    {
        return a + b;
    }
};
class Plus
{
public:
    static int plusi(int a, int b)
    {
        return a + b;
    }
    double plusd(double a, double b)
    {
        return a + b;
    }
};
int main()
{
    // 函数名(函数指针)
    std::function<int(int, int)> func1 = f;
    cout << func1(1, 2) << endl;
    // 函数对象
    std::function<int(int, int)> func2 = Functor();
    cout << func2(1, 2) << endl;
    // lamber表达式
    std::function<int(int, int)> func3 = [](const int a, const int b)
    {return a + b; };
    cout << func3(1, 2) << endl;

    // 类的成员函数
    std::function<int(int, int)> func4 = Plus::plusi;
    cout << func4(1, 2) << endl;
    std::function<double(Plus, double, double)> func5 = &Plus::plusd;
    cout << func5(Plus(), 1.1, 2.2) << endl;
    return 0;
}

 通常不会这样用,而是将包装器装在map中map<string,function<Ret(Args...)>;这样玩;组成<key,value>键值对,这样玩;


网站公告

今日签到

点亮在社区的每一天
去签到