常用的c++新特性--> day02

news/2024/11/6 10:57:01 标签: c++, 算法, 开发语言

可调用对象

案例

#include <iostream>
#include <string>
#include <vector>
using namespace std;

using funcptr = void(*)(int, string);

int print(int a, double b)
{
    cout << a << ", " << b << endl;
    return 0;
}
// 定义函数指针
int (*func)(int, double) = &print;

struct Test
{
    int m_id;
    // ()操作符重载
    void operator()(string msg)
    {
        cout << "msg: " << msg << endl;
    }

    //属于类的
    static void world(int a, string b)
    {
        cout << "name: " << b << ", age: " << a << endl;
    }

    //属于对象
    void hello(int a, string b)
    {
        cout << "name: " << b << ", age: " << a << endl;
    }

    // 将类对象转换为函数指针 ----> 指定world被调用
    operator funcptr()
    {
        //return hello;//err
        return world;
    }
};

int main(void)
{
    func(1, 2);

    Test t;
    t("hello world");

    Test tt;
    // 对象转换为函数指针, 并调用
    tt(19, "Monkey D. Luffy");
    //-----------------------------------------------------------------------------
    //类的函数指针
    //左侧是不属于类的函数指针,右侧是属于类的函数指针
    //funcptr f = Test::hello;//err
    
    //函数名就是地址 下面两个写法都对
    funcptr f1 = Test::world;
    f1(10, "冬狮郎");
    funcptr f2 = &Test::world;
    f2(0, "黑崎一护");

    using fptr = void(Test::*)(int, string);
    fptr f3 = &Test::hello;
    Test ttt;
    (ttt.*f3)(2, "碎蜂");
    //---------------------------------------------------------------
    //类的成员指针(变量)
    using ptr1 = int Test::*;
    ptr1 pt = &Test::m_id;
    ttt.*pt = 1008611;
    cout << "m_id:" << ttt.m_id << endl;

    return 0;
}

在这里插入图片描述

可调用对象包装器

std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类(非静态)成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟执行它们。

语法

#include <functional>
std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;

案例

#include <iostream>
#include <string>
#include <vector>
#include <functional>
using namespace std;

using funcptr = void(*)(int, string);

int print(int a, double b)
{
    cout << a << ", " << b << endl;
    return 0;
}
// 定义函数指针
int (*func)(int, double) = &print;

struct Test
{
    int m_id;
    // ()操作符重载 >>> 仿函数
    void operator()(string msg)
    {
        cout << "msg: " << msg << endl;
    }

    //属于类的
    static void world(int a, string b)
    {
        cout << "name: " << b << ", age: " << a << endl;
    }

    //属于对象
    void hello(int a, string b)
    {
        cout << "name: " << b << ", age: " << a << endl;
    }

    // 将类对象转换为函数指针 ----> 指定world被调用
    operator funcptr()
    {
        //return hello;//err
        return world;
    }
};

int main(void)
{
    //1、函数指针
    func(1, 2.2);

    //2、仿函数
    Test t;
    t("hello world");

    Test tt;
    //对象转换为函数指针, 并调用 >>>>>>>>>>>>>>>>>>>> operator 对应函数
    tt(19, "Monkey D. Luffy");

    //3、类的函数指针
    //左侧是不属于类的函数指针,右侧是属于类的函数指针
    //funcptr f = Test::hello;//err
    
    //函数名就是地址 下面两个写法都对
    funcptr f1 = Test::world;
    f1(10, "冬狮郎");
    funcptr f2 = &Test::world;
    f2(0, "黑崎一护");

    using fptr = void(Test::*)(int, string);
    fptr f3 = &Test::hello;
    Test ttt;
    (ttt.*f3)(2, "碎蜂");

    //4、类的成员指针(变量)
    using ptr1 = int Test::*;
    ptr1 pt = &Test::m_id;
    ttt.*pt = 1008611;
    cout << "m_id:" << ttt.m_id << endl;

//*********************************************************************************************
    cout << endl << endl << endl;
//*********************************************************************************************

    //1、包装普通函数
    function<void(int, double)>f4 = print;
    f4(1, 2.2);
    //2、包装静态函数
    function<void(int, string)>f5 = Test::world;
    f5(5, "蓝染");
    //3、包装仿函数
    Test ta;
    function<void(string)>f6 = ta;
    f6("浦原喜助");
    //4、包装转换为函数指针的对象
    Test tb;
    function<void(int, string)>f7 = tb;
    f7(11, "更木剑八");

    return 0;
}

在这里插入图片描述

可调用对象包装器作为函数参数

#include <iostream>
#include <string>
#include <vector>
#include <functional>
using namespace std;

using funcptr = void(*)(int, string);

int print(int a, double b)
{
    cout << a << ", " << b << endl;
    return 0;
}
// 定义函数指针
int (*func)(int, double) = &print;

struct Test
{
    int m_id;
    // ()操作符重载 >>> 仿函数
    void operator()(string msg)
    {
        cout << "msg: " << msg << endl;
    }

    //属于类的
    static void world(int a, string b)
    {
        cout << "name: " << b << ", age: " << a << endl;
    }

    //属于对象
    void hello(int a, string b)
    {
        cout << "name: " << b << ", age: " << a << endl;
    }

    // 将类对象转换为函数指针 ----> 指定world被调用
    operator funcptr()
    {
        //return hello;//err
        return world;
    }
};

class A
{
public:
    // 构造函数参数是一个包装器对象
    A(const function<void(int,string)>& f) : callback(f)
    {
    }

    void notify(int id, string name)
    {
        callback(id, name); // 调用通过构造函数得到的函数指针
    }
private:
    function<void(int,string)> callback;
};

int main(void)
{
    //1、函数指针
    func(1, 2.2);

    //2、仿函数
    Test t;
    t("hello world");

    //2.5、是一个可被转换为函数指针的类对象
    Test tt;
    //对象转换为函数指针, 并调用 >>>>>>>>>>>>>>>>>>>> operator 对应函数
    tt(19, "Monkey D. Luffy");

    //3、类的函数指针
    //左侧是不属于类的函数指针,右侧是属于类的函数指针
    //funcptr f = Test::hello;//err
    
    //函数名就是地址 下面两个写法都对
    funcptr f1 = Test::world;
    f1(10, "冬狮郎");
    funcptr f2 = &Test::world;
    f2(0, "黑崎一护");

    using fptr = void(Test::*)(int, string);
    fptr f3 = &Test::hello;
    Test ttt;
    (ttt.*f3)(2, "碎蜂");

    //4、类的成员指针(变量)
    using ptr1 = int Test::*;
    ptr1 pt = &Test::m_id;
    ttt.*pt = 1008611;
    cout << "m_id:" << ttt.m_id << endl;

//*********************************************************************************************
    cout << endl << endl;
//*********************************************************************************************

    //1、包装普通函数
    function<void(int, double)>f4 = print;
    f4(1, 2.2);
    //2、包装静态函数
    function<void(int, string)>f5 = Test::world;
    f5(5, "蓝染");
    //3、包装仿函数
    Test ta;
    function<void(string)>f6 = ta;
    f6("浦原喜助");
    //4、包装转换为函数指针的对象
    Test tb;
    function<void(int, string)>f7 = tb;
    f7(11, "更木剑八");

//*********************************************************************************************
    cout << endl << endl;
//*********************************************************************************************
    
    //可调用函数包装器作为函数参数
    A aa(Test::world);
    aa.notify(12, "涅茧利");

    Test tc;
    A bb(tc);
    bb.notify(7, "狛村左阵");
    return 0;
}

在这里插入图片描述
Test 类定义了一个 operator funcptr() 转换函数,它的作用是将 Test 类的对象转换为 funcptr 类型的函数指针(即 void(*)(int, string))。当将 tb 传递给 f7 时,实际上调用了这个转换操作符。

补充:类型转换运算符

operator 目标类型()
{
    // 转换逻辑
}

案例

#include <iostream>
using namespace std;

class Box {
public:
    Box(double v) : volume(v) {}

    // 类型转换运算符:将 Box 对象转换为 double 类型
    operator double() const {
        return volume;
    }

private:
    double volume;
};

int main() {
    Box b(100.0);
    double volume = b; // 隐式调用 operator double()
    cout << "Volume: " << volume << endl;
    return 0;
}

在这里插入图片描述

可调用对象绑定器

可调用对象绑定器:
1、将可调用对象与其参数一起绑定成一个仿函数。
2、将多元(参数个数为n,n>1)可调用对象转换为一元或者(n-1)元可调用对象,即只绑定部分参数。

语法格式

// 绑定非类成员函数/变量
auto f = std::bind(可调用对象地址, 绑定的参数/占位符); //>>>>>>>>>>>>>>>>静态函数可以使用这种方式
// 绑定类成员函/变量
auto f = std::bind(类函数/成员地址, 类实例对象地址, 绑定的参数/占位符);// >>>>>>>>>>>>>>>>>>>>绑定的是成员第三个参数可以省略

绑定非类成员函数/变量

案例1

#include <iostream>
#include <functional>
using namespace std;
//通过bind得到第二个参数
void callFunc(int x, const function<void(int)>& f)
{
    if (x % 2 == 0)
    {
        f(x);
    }
}
void output(int x)
{
    cout << x << " ";
}

void output_add(int x)
{
    cout << x + 10 << " ";
}

int main(void)
{
    // 使用绑定器绑定可调用对象和参数
    auto f1 = bind(output, placeholders::_1);// >>>>>> f1类型std::function<void(int)>
    for (int i = 0; i < 10; ++i)
    {
        callFunc(i, f1);
    }
    cout << endl;

    auto f2 = bind(output_add, placeholders::_1);// >>>>>>> f2类型std::function<void(int)>
    for (int i = 0; i < 10; ++i)
    {
        callFunc(i, f2);
    }
    cout << endl;

    return 0;
}

在上面的程序中,使用了std::bind绑定器,在函数外部通过绑定不同的函数,控制了最后执行的结果。std::bind绑定器返回的是一个仿函数类型,得到的返回值可以直接赋值给一个std::function,在使用的时候我们并不需要关心绑定器的返回值类型,使用auto进行自动类型推导就可以了。
placeholders::_1是一个占位符,代表这个位置将在函数调用时被传入的第一个参数所替代。同样还有其他的占位符placeholders::_2、placeholders::_3、placeholders::_4、placeholders::_5等……
在这里插入图片描述

案例2

#include <iostream>
#include <functional>
using namespace std;

void output(int x, int y)
{
    cout << x << " " << y << endl;
}

int main(void)
{
    // 使用绑定器绑定可调用对象和参数, 并调用得到的仿函数
    bind(output, 1, 2)();
    bind(output, placeholders::_1, 2)(10);
    bind(output, 2, placeholders::_1)(10);

    // error, 调用时没有第二个参数
    // bind(output, 2, placeholders::_2)(10);
    // 调用时第一个参数10被吞掉了,没有被使用
    bind(output, 2, placeholders::_2)(10, 20);

    bind(output, placeholders::_1, placeholders::_2)(10, 20);
    bind(output, placeholders::_2, placeholders::_1)(10, 20);


    return 0;
}

在这里插入图片描述

案例3

#include <iostream>
#include <functional>
using namespace std;

void callFunc(int x, int y, const function<void(int, int)>& f)
{
    if (x % 2 == 0)
    {
        f(x, y);
    }
}

void output_add(int x, int y)
{
    cout << "x: " << x << ",y: " << y <<
        ",x+y: " << x + y << endl;
}

int main(void)
{
    for (int i = 0; i < 10; ++i)
    {
        //bind绑定固定的实参函数调用的时候是不会生效的
        //如果是占位符是可以生效的
        //绑定的是output_add函数 i+100 i+200是为这个函数提供的参数
        auto f1 = bind(output_add, i + 100, i + 200);// >>>>>> f1被推导为function<void<int,int>>类型
        callFunc(i, i, f1);
        cout << endl;
        auto f2 = bind(output_add, placeholders::_1, placeholders::_2);
        callFunc(i, i, f2);
    }
    return 0;
}

在这里插入图片描述

案例4

#include <iostream>
#include <functional>
using namespace std;

void callFunc(int x, int y, const function<void(int, int)>& f)
{
    if (x % 2 == 0)
    {
        f(x, y);
    }
}

void output_add(int x, int y)
{
    cout << "x: " << x << ",y: " << y <<
        ",x+y: " << x + y << endl;
}

int main(void)
{
    for (int i = 0; i < 10; ++i)
    {
        callFunc(i, i, bind(output_add, placeholders::_1, placeholders::_2));
    }
    return 0;
}

在这里插入图片描述

绑定类成员函数/变量

#include <iostream>
#include <functional>
using namespace std;

class Test
{
public:
    void output(int x, int y)
    {
        cout << "x: " << x << ", y: " << y << endl;
    }
    int m_number = 100;
};

int main(void)
{
    Test t;
    // 绑定类成员函数
    function<void(int, int)> f1 = bind(&Test::output, &t, placeholders::_1, placeholders::_2);
    auto f2 = bind(&Test::output, &t, 14, placeholders::_1);
    // 绑定类成员变量(公共)
    //f3可读可写 >>>>>>>>> &
    function<int& (void)> f3 = bind(&Test::m_number, &t);
    auto f4 = bind(&Test::m_number, &t);// >>>>>>>>f3和f4类型不一样

    // 调用
    f1(520, 1314);
    f2(38);
    cout << "f3():" << f3() << endl;
    f3() = 2333;
    cout << "t.m_number: " << t.m_number << endl;
    f4() = 3332;
    cout << "t.m_number: " << t.m_number << endl;

    return 0;
}

在这里插入图片描述


http://www.niftyadmin.cn/n/5740796.html

相关文章

unity3d————屏幕坐标,GUI坐标,世界坐标的基础注意点

在Unity3D中&#xff0c;GUI控件的起始坐标与屏幕坐标的起始点并不完全相同&#xff0c;具体说明如下&#xff1a; GUI控件的起始坐标 绘制GUI界面时使用的坐标以屏幕的左上角为(0,0)点&#xff0c;右下角为(Screen.width, Screen.Height)。不过&#xff0c;对于GUI控件的具体…

无人机之姿态融合算法篇

无人机的姿态融合算法是无人机飞行控制中的核心技术之一&#xff0c;它通过将来自不同传感器的数据进行融合&#xff0c;以实现更加精确、可靠的姿态检测。 一、传感器选择与数据预处理 无人机姿态融合算法通常依赖于多种传感器&#xff0c;包括加速度计、陀螺仪、磁力计等。这…

[Web安全 网络安全]-DoS(拒绝服务攻击)和DDoS(分布式拒绝服务攻击)

文章目录&#xff1a; 一&#xff1a;前言 1.DoS攻击 2.DDoS攻击 3.DoS攻击和DoS攻击的异同 4.原理 5.攻击流程 6.分类 7.影响 8.防御 9.工具 二&#xff1a;攻击方式 一&#xff1a;前言 1.DoS攻击 DoS攻击&#xff0c;即拒绝服务攻击故意的攻击网络协议实现的缺…

浅谈QT中Tab键的切换逻辑

浅谈QT中Tab键的切换逻辑 无意中发现在输入界面中按下Tab键时&#xff0c;没有按照预想的顺序切换焦点事件&#xff0c;如下图所示 这个现象还是很有趣&#xff0c;仔细观察了下&#xff0c;默认的切换顺序是按照控件拖入顺序&#xff0c;那么知道了这个问题想要解决起来就很简…

C#开发流程

注&#xff1a;检查数据库链接 设置搜索 1.新建模块文件夹 对应应用 右键-添加-新建文件夹 2.新建类 在新建模块下右键 新建-类&#xff0c;修改类名称 修改internal为public 新建所需字段&#xff0c;注意类型声明及必填设置 [SugarColumn(IsNullable false)]public strin…

APP开发者如何选择合适的聚合平台?

选择合适的 App 聚合平台对于开发者而言&#xff0c;无疑是一项具有深远影响的重要决策&#xff0c;其意义之重大&#xff0c;直接关乎着 App 的收益、用户体验以及市场覆盖的广度与深度。 就拿收益这一方面来说&#xff0c;App 的收益直接决定了开发者的投入产出比以及后续的…

【数据仓库】Hive 拉链表实践

背景 拉链表是一种数据模型&#xff0c;主要是针对数据仓库设计中表存储数据的方式而定义的&#xff1b;顾名思义&#xff0c;所谓拉链表&#xff0c;就是记录历史。记录一个事务从开始一直到当前状态的所有变化的信息。 拉链表可以避免按每一天存储所有记录造成的海量存储问题…

青少年编程与数学 02-003 Go语言网络编程 11课题、Go语言网络编程

青少年编程与数学 02-003 Go语言网络编程 11课题、Go语言网络编程 课题摘要:一、Go语言与网络编程二、Go语言网络编程分类1. 按协议分类2. 按应用层级分类3. 按服务类型分类4. 按并发模型分类5. 按编程范式分类6. 按安全需求分类7. 按性能要求分类8. 按开发框架分类 三、Go语言…