IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 函数指针 -> 正文阅读

[C++知识库]函数指针

如何定义一个函数指针

  1. 什么是函数指针 ?
    如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫做函数指针变量,简称函数指针

  2. 指针变量如何定义呢 ?
    虽然同样是指向一个地址,但是指向函数的指针变量同我们之前的指向变量的指针变量的定义方式是不同的。例如:

    int (*p)(int ,int)
    

    这个语句就定义了一个指向函数的指针变量 p ,首先它是一个指针变量,所以要有一个 “*” ,即 (*p) ; 其次前面的这个 int 表示这个指针变量可以指向返回值类型为 int 的函数 ; 后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型 的函数。所以合起来这个语句的意思就是:定义了一个指针变量 p ,该指针变量可以指向返回类型为 int ,且有两个整型参数的函数。p 的类型为 int (*)(int, int)

    所以函数指针的定义方式为:

    函数返回值类型 (*指针变量名) (函数参数列表)
    

    “函数返回值类型” 表示该指针变量可以指向具有什么返回值类型的函数;“函数参数列表” 表示该指针变量可以具有什么参数列表的函数。这个参数列表中只需要写函数的参数类型即可。

    我们看到,函数指针的定义就是将“函数声明”中的“函数名”改成“(*指针变量名)”。但是这里需要注意的是:“(*指针变量名)”两端的括号不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针而是一个函数声明了,即声明了一个返回值类型为指针型的函数。

    那么怎么判断一个指针变量是指向变量的指针变量还是指向函数的指针变量呢?首先看变量名前面有没有“”,如果有“”说明是指针变量;其次看变量名的后面有没有带有形参类型的圆括号,如果有就是指向函数的指针变量,即函数指针,如果没有就是指向变量的指针变量。

  3. 如何利用函数指针调用函数 ?

    int Func(int x);   /*声明一个函数*/
    int (*p) (int x);  /*定义一个函数指针*/
    p = Func;          /*将Func函数的首地址赋给指针变量p*/
    

    赋值时函数 Func 不带括号,也不带参数。由于函数名 Func 代表函数的首地址,因此经过赋值以后,指针变量 p 就指向函数 Func() 代码的首地址了。

std::function 的用法 ?

类模板 std::function 是一种通用、多态的函数封装。std::function 的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda 表达式、函数指针、以及其它函数对象等。std::function 对象是对 C++中现有的可调用实体的一种类型安全的包裹(我们只掉像函数指针这类可调用实体,是类型不安全的)。

通常 std::function 是一个函数对象类,它包装其它任意的函数对象,被包装的函数对象具有类型为 T1,TN 的 N 个参数,并且返回一个可以转换到 R 类型的值。std::function 使用模板转换构造函数接收被包装的函数对象;特别是,闭包类型可以隐式地转换为 std::function

通过 std::function 对 C++ 中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新的可调用的 std::function 对象;让我们不再纠结那么多的可调用实体。一切变得简单粗暴。

关于可调用的实体转换成 std::function 类型的对象,的注意事项:

  • 关于可调用实体转换为 std::function 对象需要需要遵守以下两条原则
  • 转换后的 std::function 对象的参数能转换为可调用实体的参数
  • 可调用实体的返回值能转换为 std::function 对象的返回值
  • std::function 对象最大的用处就是在实现函数回调,使用者需要注意,他不能被用来检查相等或者不相等,但是可以与NULL或者nullptr进行比较。
#include<iostream>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<string>
#include<algorithm>
#include<functional>
#include<memory>

using namespace std;

typedef std::function<int(int)> Functional;

//normal function
int TestFunc(int a)
{
	return a;
}

//lambda expression
auto lambda = [](int a)->int {return a; };

//functor 仿函数
class Functor
{
public:
	int operator()(int a)
	{
		return a;
	}
};

//类的成员函数和类的静态成员函数
class CTest
{
public:
	int Func(int a)
	{
		return a;
	}
	static int SFunc(int a)
	{
		return a;
	}
};

int main(int argc, char* argv[])
{
	//封装普通函数
	Functional obj = TestFunc;
	int res = obj(0);

	cout << "normal function : " << res << endl;


	//封装 lambda 表达式
	obj = lambda;
	res = obj(1);
	cout << "lambda expression : " << res << endl;

	//封装仿函数
	Functor functorobj;
	obj = functorobj;
	res = obj(2);
	cout << "functor : " << res << endl;

	//封装类的成员函数和static成员函数
    //类普通成员函数比较特殊,需要使用 bind 函数 , 并且需要实例化对象,成员函数要       加取地址符
	CTest t;
	obj = std::bind(&CTest::Func, &t, std::placeholders::_1);
	res = obj(3);
	cout << "member  function : " << res << endl;

	obj = CTest::SFunc;
	res = obj(4);
	cout << "static member function : " << res << endl;

	return 0;
}

std::bind 介绍

std::bind 函数将可调用对象和可调用对象的参数进行绑定,返回新的可调用对象(std::function 类型,参数列表可能改变),返回的新的std::function可调用对象的参数列表根据bind函数实参中std::placeholders::_x从小到大对应的参数确定

参考下面代码:

#include<iostream>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<string>
#include<algorithm>
#include<functional>
#include<memory>

using namespace std;

class A 
{
public:
	void fun_3(int k, int m)
	{
		cout << k << " " << m << endl;
	}
};

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

void fun_2(int& a, int& b)
{
	a++;
	b++;
	cout << a << " " << b << endl;
}

int main(int argc , char ** argv)
{
	auto f1 = std::bind(fun, 1, 2, 3); //表示绑定函数 fun 的第一, 二 , 三个参数值为:1 , 2 , 3
	f1();  //print: 1 , 2 , 3

	//表示绑定函数 fun 的第三个参数为3,而fun 的第一,二个参数分别有调用 f2 的第一,二个参数指定
	auto f2 = std::bind(fun, placeholders::_1, placeholders::_2, 3);
	f2(1, 2); //print: 1 , 2 , 3

	//表示绑定函数 fun 的第三个参数为3,而fun 的第一,二个参数分别有调用 f3 的第二,一个参数指定
	auto f3 = std::bind(fun, placeholders::_2, placeholders::_1, 3);
	f3(1, 2); //print: 2 , 1 , 3

	int n = 2, m = 3;
	auto f4 = std::bind(fun_2, n, placeholders::_1);
	f4(m);  //print: 3 , 4

	cout << m << endl; //print 4  说明:bind 对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的
	cout << n << endl; //print 2  说明: bind 对于预先绑定的函数参数是通过值传递的

	//成员函数的绑定,比较常用,作为回调
	A a;
	auto f5 = std::bind(&A::fun_3, a, placeholders::_1, placeholders::_2);
	f5(10, 20);

	std::function<void(int, int)> fc = std::bind(&A::fun_3, a, std::placeholders::_1, std::placeholders::_2);
	fc(10, 20);//print:10 20

	return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:03:43  更:2021-09-29 10:05:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 4:41:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计