返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++可调用对象callableobject深入分析
  • 115
分享到

C++可调用对象callableobject深入分析

2024-04-02 19:04:59 115人浏览 独家记忆
摘要

目录为什么需要他他究竟是啥他怎样被使用呢本作者一致的观点就是 在任何语言执行的时候先去思考汇编层面能不能做到 如果能做到 那么高级语言才能做到 无论你推出什么新特性 用户态汇编你都是

本作者一致的观点就是 在任何语言执行的时候先去思考汇编层面能不能做到 如果能做到 那么高级语言才能做到 无论你推出什么新特性 用户态汇编你都是绕不开的 比如你要调用函数 那么你必须要使用call指令 那么就必须要有函数地址 接下来我们来详细说说为什么c++11要推出这个新概念 以及他解决了什么问题 还有如何使用它

Tips:c++的设计哲学是你必须时刻清楚你自己在干什么 stl内部并不会给你执行任何的安全检查 程序直接崩溃也是完全有可能的 功力不够 就不要玩花的

为什么需要他

在c++11还没有推出callable object的时候 那时候如果你想要把普通函数当做参数一样传递那么你就只能使用函数指针 如下段代码所示

我就不再演示如果你有函数指针如何调用函数了 空指针发生调用异常啥的也是你自己的问题那非常简单了 不需要过多描述

注意 FuncP是一种类型 而非一个指针

#include <iOStream>
void test(int i)
{
	return;
}
typedef void(*FuncP)(int i);
void recevier(void(*)(int))
{
	std::cout << "recevier working!" << std::endl;
}
int main()
{
	recevier(&test);
	FuncP ding = test;
	recevier(&test);
	void(*FuncP1)(int) = test;
	recevier(FuncP1);
}

运行结果截图:

而如果你想把类的成员函数传递 那更是麻烦 因为我们知道类的成员函数在调用的时候是需要传递this指针的 那么我们来看一看如何传递类的成员函数 如下段代码所示

#include <iostream>
class testclass
{
public:
	void MemberFunc(int i)
	{
		std::cout << "MemberFunc" << std::endl;
	}
};
typedef void(testclass::* CFuncP)(int);
void recevier(void(testclass::* memberFunc)(int))
{
	testclass p;
	(p.*memberFunc)(1);
	std::cout << "recevier working!" << std::endl;
}
void recevier(void(*)(int))
{
	std::cout << "recevier working!" << std::endl;
}
int main()
{
	recevier(&testclass::MemberFunc);
	CFuncP ding = &testclass::MemberFunc;
	recevier(ding);
	void(testclass:: * testF)(int) = &testclass::MemberFunc;
	recevier(testF);
}

运行结果如下图

可以看到啊 虽然咱们用普通的成员函数指针和普通的函数指针似乎已经可以解决绝大部分问题 那为什么又要推出一个callable object呢? 关键在于这种代码实现起来 其实可读性很差 而且不是那么好理解 如果有一种统一的方式来让我们可以把函数当做参数传递 并且能直接调用就好了 那么c++11便推出了callable object

他究竟是啥

那么究竟什么叫做callable object呢 顾名思义 就是可以被调用的对象 看如下一个最简单的例子

#include <iostream>
class testclass
{
public:
	void MemberFunc(int i)
	{
		std::cout << "MemberFunc" << std::endl;
	}
	void operator()()
	{
		std::cout << "callable object working" << std::endl;
	}
};
int main()
{
	testclass ding;
	ding();
}

当一个对象 重载了() 运算符的时候 我们就把他看做 一个最简单的callable object 因为他这个对象可以像函数一样被调用是吧 没有什么问题 那么接下来我们就来看看stl提供的 能让你快速生成callable object的组件之std::bind

他怎样被使用呢

我们先来看一个最简单的例子 基于std::bind

void test(int i, int j, int k)
{
	std::cout << "test working!" << std::endl;
	std::cout << i << std::endl;
	std::cout << j << std::endl;
	std::cout << k << std::endl;
}
int main()
{
	std::bind(&test, 1, 2, 3)();
}

如上图所示 我们使用std::bind来创建了一个callable object并且在创建这个callable object的时候就已经把他三个参数传递好了 这点非常重要 这会影响到接下来的占位符的讲解 然后马上使用()来调用了他 运行结果如下图所示

相比较于普通的函数指针 这样的方式是不是更简单明了了呢? 当然这远远不是他的全部 接下来我们来看看使用占位符的时候 该如何使用它 代码如下图所示

void test(int i, int j, int k)
{
	std::cout << "test working!" << std::endl;
	std::cout << i << std::endl;
	std::cout << j << std::endl;
	std::cout << k << std::endl;
}
int main()
{
	std::bind(&test, 1,std::placeholders::_1,std::placeholders::_2)(2,3);
}

可以看到上图 我们在创建callable object的时候 并没有去传递全部的参数 而是使用了占位符 然后在真正调用的时候才去传递了2和3两个参数 运行结果如下图所示

下面让我们升华到成员函数好嘛? 不过多讲解 咱们直接看代码

#include <iostream>
#include <functional>
class testclass
{
public:
	void MemberFunc(int i,int j,int k)
	{
		std::cout << "MemberFunc" << std::endl;
		std::cout << i << std::endl;
		std::cout << j << std::endl;
		std::cout << k << std::endl;
	}
	void operator()()
	{
		std::cout << "callable object working" << std::endl;
	}
};
int main()
{
	std::bind(&testclass::MemberFunc, testclass(), 1, std::placeholders::_1, std::placeholders::_2)(2, 3);
}

成员函数的调用时需要this指针的 我相信大家都知道 那么这就是为什么我在std::bind的第二个参数创建了一个临时对象 用来传递this指针 可以看到相比较于普通的成员函数指针 这种方式明显要方便的多 注意啊 使用std::bind来创建成员函数的callable object的时候 第二个参数必须是对象或者某个对象的this指针 不然直接会G的

乱玩导致的G 你自己负责 如下图所示

当然 像下图这样先使用占位符将传入对象暂定 然后在参数中去传递对象或this指针也是可以的

std::bind
(&testclass::MemberFunc,std::placeholders::_1, 1, std::placeholders::_2,
std::placeholders::_3)(testclass(),2, 3);

这个时候你就要问了 OK 这样确实很方便 没错 但是你说了这么久也没见你把它当做参数来传递啊 下面就来介绍std::function 他不仅能当做参数来传递 并且还可以保存callable object 属实是非常方便 老样子 还是从最简单的例子开始 代码如下图

#include <iostream>
#include <functional>
class testclass
{
public:
	int ding{};
	void MemberFunc(int i,int j,int k)
	{
		std::cout << "MemberFunc" << std::endl;
		std::cout << i << std::endl;
		std::cout << j << std::endl;
		std::cout << k << std::endl;
		std::cout << ding << std::endl;
	}
	void operator()()
	{
		std::cout << "callable object working" << std::endl;
	}
};
int main()
{
	std::function<void(int,int,int)>MemberCall=std::bind(&testclass::MemberFunc,testclass(), 1, std::placeholders::_1, std::placeholders::_2);
	MemberCall(1,2,NULL);
	std::function<void(testclass&, int, int, int) > MemberCall2=&testclass::MemberFunc;
	testclass C;
	MemberCall2(C, 1, 1, 1);
}

如上图所示 因为我已经放置了一个占位符 所以呢 第三个参数无论你填什么 都是没用的 只会取前两个参数 调用结果如下所示:

我们再来试试将他作为参数传递 很简单咯 玩起来

void test(std::function<void(int, int, int)>& Func, int c)
{
	Func(1, 2, 3);
	std::cout << c<<std::endl;
}
int main()
{
	std::function<void(int,int,int)>MemberCall=std::bind(&testclass::MemberFunc,testclass(), 1, std::placeholders::_1, std::placeholders::_2);
	MemberCall(1,2,NULL);
	std::function<void(testclass&, int, int, int) > MemberCall2=&testclass::MemberFunc;
	testclass C;
	MemberCall2(C, 1, 1, 1);
	test(MemberCall, 3);
}

运行结果如下:

看看 有了std::function和std::bind 函数就像对象一样可以被传递保存和调用 是不是很方便呢

Tips:既然他是一个对象了 那任何对对象的操作对于他都是允许的 比如塞入队列啥的 可以任意交互 其他东西我就不演示了 对于对象的各种操作是基本知识

最后让我们来看看他跟lambda之间的化学反应 代码如下:

#include <iostream>
#include <functional>
class testclass
{
public:
	int ding{};
	void MemberFunc(int i,int j,int k)
	{
		std::cout << "MemberFunc" << std::endl;
		std::cout << i << std::endl;
		std::cout << j << std::endl;
		std::cout << k << std::endl;
		std::cout << ding << std::endl;
	}
	void operator()()
	{
		std::cout << "callable object working" << std::endl;
	}
};
void test(std::function<void(int, int, int)>& Func, int c)
{
	Func(1, 2, 3);
	std::cout << c<<std::endl;
}
int main()
{
	std::function<void(int,int,int)>MemberCall=std::bind(&testclass::MemberFunc,testclass(), 1, std::placeholders::_1, std::placeholders::_2);
	std::function<void(testclass&&,int, int, int)>MemberCall1 = std::bind(&testclass::MemberFunc, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,std::placeholders::_4);
	MemberCall1(testclass(),1, 2, 3);
	MemberCall(1,2,3);
	std::function<void(testclass&, int, int, int) > MemberCall2=&testclass::MemberFunc;
	testclass C;
	MemberCall2(C, 1, 1, 1);
	test(MemberCall, 3);
	std::function<bool(int,int,int)> play=std::bind([&C](testclass& c, int i, int j, int k)->bool {
		c.MemberFunc(i, j, k);
		std::cout << "lambda working!" << std::endl;
		}, C, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
	play(1, 2, 3);
}

运行结果如下

相信细心的小伙伴已经发现我多加了一个Membercall1 并且使用了右值引用 关于这个 我们下一篇文章再说好嘛? 本期callable object讲解结束 认真看完相信你能学到很多东西

到此这篇关于C++可调用对象callable object深入分析的文章就介绍到这了,更多相关C++ callable object内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++可调用对象callableobject深入分析

本文链接: https://lsjlt.com/news/165949.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++可调用对象callableobject深入分析
    目录为什么需要他他究竟是啥他怎样被使用呢本作者一致的观点就是 在任何语言执行的时候先去思考汇编层面能不能做到 如果能做到 那么高级语言才能做到 无论你推出什么新特性 用户态汇编你都是...
    99+
    2024-04-02
  • C++深入刨析类与对象的使用
    目录this指针this指针存放在哪nullptr与类类的默认成员函数构造函数意义析构函数拷贝构造运算符重载this指针 现在给出一段代码,实现一个普通的日期 date 的打印: c...
    99+
    2024-04-02
  • 深入浅出分析Java类和对象
    目录一、什么是类二、Java的类和C语言的结构体异同三、类和类的实例化类的声明实例化的对象,成员遵循默认值规则类的实例化静态属性(静态成员变量)四、构造方法创建构造方法this一、什...
    99+
    2024-04-02
  • Java 类与对象:对象导向编程的基石(深入分析)
    : 类:对象的蓝图 类是描述一组具有相同特征和行为的对象的模板。它定义了对象的属性(数据成员)和方法(行为)。类是抽象概念,不能直接实例化。 创建类: class Employee { private String name; ...
    99+
    2024-03-09
    : Java、类、对象、OOP、封装、继承、多态
  • C++中对象&类的深入理解
    什么是对象 任何事物都是一个对象, 也就是传说中的万物皆为对象. 对象的组成: 数据: 描述对象的属性 函数: 描述对象的行为, 根据外界的信息进行相应操作的代码...
    99+
    2024-04-02
  • 深入浅析Java中的对象与引用
    今天就跟大家聊聊有关深入浅析Java中的对象与引用,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java中的对象和引用详解 在Java中,有一组名词经常一起出现,它们就是“对象和对象...
    99+
    2023-05-31
    java 对象 引用
  • 深入浅析Java中的对象流
    这期内容当中小编将会给大家带来有关深入浅析Java中的对象流,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java中可以通过对象流将一个序列化的对象保存到硬盘中,或者硬盘中读取一个对象。对象流的存储和读取...
    99+
    2023-05-31
    java 对象流 ava
  • C++深入讲解对象的销毁之析构函数
    目录一、对象的销毁二、析构函数三、小结一、对象的销毁 生活中的对象都是被初始化后才上市的生活中的对象被销毁前会做一些清理工作—股而言,需要销毁的对象都应该做清理 解决方案...
    99+
    2024-04-02
  • JavaScript 错误对象:深入分析其属性和方法
    JavaScript 错误对象是执行 JavaScript 代码时产生的异常的表示。它提供了有关错误详细信息的丰富信息,开发人员可以使用这些信息来调试和处理错误。本文深入探讨了 JavaScript 错误对象的属性和方法,帮助开发人员更...
    99+
    2024-03-05
    JavaScript 错误对象、属性、方法、错误处理
  • 【C++深入浅出】类和对象下篇
    一. 前言         老样子,先来回顾一下上期的内容:上期我们着重学了C++类中的六大默认成员函数,并自己动手实现了一个日期类,相信各位对C++中的类已经有了一定程度的了解。本期就是类和对象的最后一篇啦,终于要结束咯,吧唧吧唧  ...
    99+
    2023-10-10
    c++ 开发语言 初始化列表 static成员 友元 匿名对象 explicit关键字
  • 深入浅析java中的面向对象
    本篇文章给大家分享的是有关深入浅析java中的面向对象,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一.面向对象(OO)面向对象(OO):就是基于对象概念,以对象为中心,以类和...
    99+
    2023-05-31
    面向对象 java ava
  • C++ 函数调用详解:参数传递机制深入分析
    c++++ 函数调用有三种参数传递机制:传值调用(复制参数值),传引用调用(传递参数引用,可修改原始变量),指针传递(传递参数指针)。选择机制需考虑参数大小、是否需修改原始变量和效率。 ...
    99+
    2024-05-04
    c++ 函数调用
  • C++中的类与对象深度解析
    目录初始化列表引论初始化列表explicit关键字引论explicit关键字使用static成员 友元引论友元内部类基础概念内部类的使用补充析构顺序例题总结初始化列表 引论...
    99+
    2024-04-02
  • Python中可变和不可变对象的深入讲解
    目录前置知识 有哪些可变对象,哪些不可变对象? 不可变对象和可变对象的区别? 不可变对象的应用场景 从内存角度出发说下有什么区别? 不可变对象可变对象从代码角度看看区别 不可变对象...
    99+
    2024-04-02
  • C#如何调用COM对象
    这篇文章主要介绍C#如何调用COM对象,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!C#调用COM对象我们曾经在以前的应用中多次需要得到SQL Server的详细信息,过去,我们必须使用API和效率低下的ADO的调用...
    99+
    2023-06-17
  • C++深入分析讲解链表
    目录链表的概述1、数组特点2、链表的概述3、链表的特点静态链表链表的操作1、链表插入节点头部之前插入节点尾部之后插入节点有序插入节点2、遍历链表节点3、查询指定节点4、删除指定节点5...
    99+
    2024-04-02
  • 深入解析Python中的__builtins__内建对象
    如果你已经学习了包,模块这些知识了。 你会不会有好奇:Python为什么可以直接使用一些内建函数,不用显式的导入它们,比如 str() int() dir() ...? 原因是Python解释器第一次启动的...
    99+
    2022-06-04
    内建 对象 Python
  • C++临时对象实例分析
    这篇“C++临时对象实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++临时对象实例分析”文章吧。一、初探临时对象1...
    99+
    2023-06-30
  • C++类与对象实例分析
    这篇“C++类与对象实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++类与对象实例分析”文章吧。运算符重载C++语...
    99+
    2023-06-30
  • c++ vector对象的示例分析
    这篇文章主要介绍c++ vector对象的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!vector对象  为什么需要vector?封装任何类型的动态数组,自动创建和删除。数组下标越界检查。封装的如Array...
    99+
    2023-06-06
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作