【C/C++】函数作为参数

C++中,函数的名字本身就是该函数的指针,函数名代表函数的入口地址, 是可以作为参数传入函数的。



一、函数指针的定义

函数类型 (*自定义变量名)(形参1,形参2...) ;
               
int (*p)(int, int);		// 定义一个指向函数的指针-->p,被指向的函数有两个整型参数并返回整型值。

上式可以看作这样:

int (*)(int, int)  p;	

其中,int (*)(int, int) 是变量类型, p是变量名。

例1:

#include<iostream>
using namespace std;

int  main()
{
	int add(int x, int y);
	int a = 2, b = 3, sum;

	// 定义一个指向函数的指针-->p,被指向的函数有两个整型参数并返回整型值。
	int(*p)(int x, int y);
	p = add;	// p指向一个函数的起始地址,它相当于一个函数的"别名"。可以写成p = &add;

	sum = add(a, b);
	cout << "sum: " << sum << endl;

	sum = p(a, b);
	cout << "sum: " << sum << endl;

	sum = (*p)(a, b);		// (*p)() == (*&add)() == add()
	cout << "sum: " << sum << endl;

	return 0;
}

int add(int x, int y) {
	return (x + y);
}

函数输出:

sum: 5
sum: 5
sum: 5

函数名代表函数的入口地址。

函数指针,指向一个函数的起始地址,它相当于一个函数的别名,它的返回值是int型(不是指针)

p = add;  // 有一层默认的转换,实际上是 p = &add; 

(*p)() == (*&add)() == add()

注意:下面这三种写法是等价的。

int(*p)(int x, int y);	p = add;

int(*p)(int x, int y) = add;
int(*p)(int x, int y) = &add;		

因为形参名可以不写,在代码中,也可以写成下面这样,也能得到同样的输出:

int(*p)(int, int);	p = add;

int(*p)(int, int) = add;
int(*p)(int, int) = &add;

可以看作

int(*)(int, int) p = &add;	//形如 int a = 3;




二、函数作为形参的语法格式

例2:

#include<iostream>
using namespace std;

// 其中: void (*)(int) 为形参的类型,func 为形参变量。
void foo(void (*func)(int),int j)
{
    func(j);
}

void printnumber(int j)
{
    cout<<"j="<<j<<" "<<endl;
}

int main()
{
    void (*func)(int i);		// 声明一个函数的指针变量--func,该函数有一个int型的参数,无返回值。
    func = printnumber;			// 将printnumber的地址赋给func。
    foo(func,1);//(1)
    foo(printnumber,1);//(2)
    // (1)、(2)两种写法是等价的。
}

个人觉得,可以将

void foo( void (*func)(int), int j)

看作

void foo( void (*)(int)  func, int j)




三、typedef定义新的函数类型

例3:用typedef定义一类函数,Linux中最常用

#include<iostream>
using namespace std;

typedef void(*func)(int, int);
//这样func就可以代表一类函数;

//使用这个定义
void runfunc(func p, int a, int b)
{
	p(a, b);
}

void add(int a, int b)
{
	cout << a + b << endl;
}

void sub(int a, int b)
{
	cout << a - b << endl;
}

int main() {
	//函数作参数
	runfunc(add, 1, 2);

	runfunc(sub, 1, 2);

	return 0;
}

个人觉得,可以将

typedef void(*func)(int, int);

看作

typedef void(*)(int, int)  func;

这样 func 就可以代表一类函数。




四、类成员函数指针的使用方法

例4:

#include<iostream>
using namespace std;

class A {
public:
	void fun(int a)
	{
		cout << a << endl;
	}
};

int main()
{
	A a;
	void (A::*ptrfun)(int);
	ptrfun = &A::fun;
	(a.*ptrfun)(2);

	return 0;
}

如果 void fun(int a) 是普通函数,对普通函数指针进行赋值时,直接写成pfun = fun。 但是,如果 void fun(int a) 是类的成员函数,对类的成员函数指针进行赋值时,必须写成pfun = &A::fun

这涉及到函数类型与函数指针类型。对于普通函数,当定义了一个函数指针,将函数名赋值给函数指针,函数类型会默认转换成函数指针。因此 pfun = fun 或者 pfun = &fun 都是可行的,只是 pfun = fun 中有一层默认的转换

而对于类的成员函数,当定义了一个成员函数指针 ptrfun,如果直接用 A::fun 进行赋值,编译器会将它理解为A中的静态成员,会产生编译错误,所以,这里的&是必须的

不过,如果写成这样 ptrfun = &(A::fun);也会发生编译错误,因为,将 A::fun 作为一个整体,编译器就会将fun理解为A中的静态成员,所以,要将 &A::fun 作为一个整体,即使::的优先级较高。同样,对于调用方式也有类似的不同。对于普通函数,(*pfun)()和pfun()都是可以的。对于成员函数,只能是 (a.*ptrfun)()




五、使用类成员函数的指针作为参数

例5:

#include<iostream>
using namespace std;

class A {
public:
	void fun(int a)
	{
		cout << a << endl;
	}
};

void test(A x, void (A::*pfun)(int), int y)
{
	(x.*pfun)(y);
}

int main()
{
	void (A::*ptrfun)(int);
	ptrfun = &A::fun;
	A a;
	test(a, ptrfun, 3);

	return 0;
}



例6:类成员函数和函数重载版本

函数重载:同一个作用域下,函数名称相同。重载函数的参数个数、参数类型或者参数顺序,三者中必须至少有一个不同。
注意: 函数的返回值不可以作为函数重载的条件。

#include<iostream>
using namespace std;

class A {
public:
	void fun1(int a)
	{
		cout << a << endl;
	}

	int fun2(int a)
	{
		cout << "this的值: " << this << endl;
		cout << a << endl;
		return a;
	}
};

void test(A x, void (A::*pfun)(int), int y)
{
	(x.*pfun)(y);
}

// test函数的重载版本,x是引用
void test(A &x, int (A::*pfun)(int), int y)
{
	(x.*pfun)(y);
}

int main()
{
	void (A::*ptrfun)(int);
	ptrfun = &A::fun1;
	A a;
	test(a, ptrfun, 3);

	cout << "------分割线------"<< endl;
	test(a, &A::fun2, 4);
	cout << "&a的值: " << &a << endl;

	return 0;
}

代码输出:
3
------分割线------
this的值: 003BFA73
4
&a的值: 003BFA73


类的成员函数存储方式

  不论类的成员函数,在类内定义还是在类外定义,成员函数的代码段的存储方式是相同的,都不占用对象的存储空间。 当程序运行时,才会给类的成员函数分配地址。 当对象 a 调用类的成员函数 fun2() 时,this 指针就指向 a,类的成员函数就会访问 a 的数据成员。

  可以看出,通过对 test 函数进行重载,可以实现:调用不同类型的类成员函数的效果。对象 a,只是给类的成员函数提供 this 指针。这样可以确保类的成员函数 fun2() 访问的是 a 的成员变量。




补充知识:this指针

  每一个成员函数都包含一个特殊的指针,这个指针指针的名字是固定的,称为this。它是指向本类对象的指针,它的值是当前被调用对象的起始地址。 this指针是隐式调用的,它是作为参数被传递给成员函数的。假如,原本的成员函数volume的定义是:

int Box::volume() {
	return h * w * l;
}

C++把它处理为

int Box::volume(Box *this) {
	return this->h * this->w * this->l;
}

在调用该成员函数时,实际上是用已下的方式调用的:

a.volume(&a);

将对象a的地址传给形参this指针。然后按this的指向去引用其他成员。




参考链接:
函数作为参数
函数参数与函数作为参数
将成员函数作为函数形参
C++typedef的详细用法
c++将函数作为函数参数(函数指针)

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值