函数指针

一、函数指针

参考:(1)C++ 函数指针 & 类成员函数指针https://www.runoob.com/w3cnote/cpp-func-pointer.html

《C++ Primer 第五版》6.7章

1、函数指针的定义方式

data_types (*func_pointer)( data_types arg1, data_types arg2, ...,data_types argn);

举例

int (*fp)(int a); // 这里就定义了一个指向函数(这个函数参数仅仅为一个 int 类型,函数返回值是 int 类型)的指针 fp。

实例

#include<iostream>
using namespace std;

int test(int a)
{
	return a;
}

int main()
{
	int (*fp)(int a);//声明,未初始化
	//fp = test;//定义
	fp = &test;//与fp = test等同
	cout << fp(2) << endl;
	cout << (*fp)(3) << endl;//此种写法更体现函数指针
	return 0;
}

2、typedef 定义可以简化函数指针的定义

#include<iostream>
using namespace std;

int test(int a)
{
	return a;
}

int main()
{
	/**
	typedef int (*fp)(int a);
	fp f = test;
	cout << f(2) << endl;
	*/
	/**
	using fp = int(*)(int);//这种写法更直观 推荐写法
	fp f = test;
	cout << f(2) << endl;
	*/
	typedef decltype(test) *fp;//decltype可返回函数类型
	fp f = test;
	cout << (*f)(2) << endl;

	return 0;
}

3、 函数指针同样是可以作为参数传递给函数的

#include<iostream>
using namespace std;

int test(int a)
{
	return a;
}

int test2(int(*fun)(int),int a, int b)//fun是个指针,无法携带参数,其指向函数的参数,必须单独传入
{
	int c = (*fun)(a) + b;
	return c;
}

int main()
{
	using fp = int(*)(int);
	fp f = &test;
	cout << test2(f, 10,1)<<endl;
	cout << test2(&test, 10, 1)<<endl;//test函数直接传入test函数
	return 0;
}

4、返回指向函数的指针的函数

#include<iostream>
using namespace std;

int test(int a)
{
	return a;
}
/**错误的函数定义方式
int (*fun1)(int)
{
	return test;
}
*/

//以下函数的本质是返回一个指向某函数的指针
int (*fun1())(int)
{
	return test;
}

using funPointer = int (*)(int);
funPointer fun2()//这种声明方式更直观,fun2函数返回一个指针,这个指针指向一个函数
{
	return test;//返回函数地址
}

int main()
{
	cout << "test " << test(1)<< endl;
	cout << "fun1 " << fun1()(2) << endl;
	cout << "fun1 " << (*fun1)()(2) << endl;
	cout << "fun2 " << fun2()(3) << endl;
	cout << "fun2 " << (*fun2)()(3) << endl;
	return 0;
}

5、利用函数指针,我们可以构成函数指针数组,更明确点的说法是构成指向函数的指针数组

void t1(){cout<<"test1"<<endl;}
void t2(){cout<<"test2"<<endl;}
void t3(){cout<<"test3"<<endl;}
 
int main(int argc, const char * argv[])
{
    
    //typedef void (*fp)(void);
    using fp=void(*)(void);
    fp b[] = {t1,t2,t3}; // b[] 为一个指向函数的指针数组
    b[0](); // 利用指向函数的指针数组进行下标操作就可以进行函数的间接调用了
    
    return 0;
}

二、指向类成员函数的指针

**定义:**类成员函数指针(member function pointer),是 C++ 语言的一类指针数据类型,用于存储一个指定类具有给定的形参列表与返回值类型的成员函数的访问信息。

基本上要注意的有两点:

  • 1、函数指针赋值要使用 &
  • 2、使用 .* (实例对象)或者 ->*(实例对象指针)调用类成员函数指针所指向的函数

A) 类成员函数指针指向类中的非静态成员函数

对于 **nonstatic member function (非静态成员函数)**取地址,获得该函数在内存中的实际地址

对于 virtual function(虚函数), 其地址在编译时期是未知的,所以对于 virtual member function(虚成员函数)取其地址,所能获得的只是一个索引值

#include<iostream>
using namespace std;

class A
{
public:
	A(int aa = 0) :a(aa) {}
	~A() {}
	void setA(int aa = 1)
	{
		a = aa;
	}
	virtual void print()
	{
		cout << "A: " << a << endl;
	}
	virtual void print1()
	{
		cout << "A1: " << a << endl;
	}

private:
	int a;
};

class B :public A
{
public:
	B() :A(), b(0) {}
	B(int aa, int bb) :A(aa), b(bb) {}
	~B() {}

	virtual void print()
	{
		A::print();
		cout << "B: " << b << endl;
	}
	virtual void print1()
	{
		A::print1();
		cout << "B1: " << b << endl;
	}

private:
	int b;
};


int main(int argc, const char* argv[])
{
	A a;
	B b;
	void (A:: * ptr)(int) = &A::setA;
	A* pa = &a;
	//对于非虚函数,返回其在内存的真实地址
	printf("A::set(): %p\n", &A::setA);
	//对于虚函数, 返回其在虚函数表的偏移位置
	printf("B::print(): %p\n", &A::print);
	printf("B::print1(): %p\n", &A::print1);

	a.print();
	a.setA(10);
	a.print();
	a.setA(100);
	a.print();
	//对于指向类成员函数的函数指针,引用时必须传入一个类对象的this指针,所以必须由类实体调用
	(pa->*ptr)(1000);
	a.print();

	(a.*ptr)(10000);
	a.print();

	return 0;
}

B) 类成员函数指针指向类中的静态成员函数

#include<iostream>
using namespace std;

class A
{
public:
	//p1是一个指向非static成员函数的函数指针
	void (A::*p1)(void);
	//p2是一个指向static成员函数的函数指针
	void (*p2)(void);
    A() {
        /*对
         **指向非static成员函数的指针
         **和
         **指向static成员函数的指针
         **的变量的赋值方式是一样的,都是&ClassName::memberVariable形式
         **区别在于:
         **对p1只能用非static成员函数赋值
         **对p2只能用static成员函数赋值
         **
         **再有,赋值时如果直接&memberVariable,则在VS中报"编译器错误 C2276"
         **参见:http://msdn.microsoft.com/zh-cn/library/850cstw1.aspx
         */
        p1 = &A::funa; //函数指针赋值一定要使用 &
        p2 = &A::funb;

        //p1 =&A::funb;//error
        //p2 =&A::funa;//error

        //p1=&funa;//error,编译器错误 C2276
        //p2=&funb;//error,编译器错误 C2276
    }

    void funa(void)
    {
        puts("A");
    }

	static void funb(void)
	{
		puts("B");
	}
};

int main(int argc, const char* argv[])
{
	A a;
	//p是指向A中非static成员函数的函数指针
    void(A:: * p)(void);

    (a.*a.p1)();//注意指针(a.p1)指向A类成员函数funa;
    //使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数
    p = a.p1;
    (a.* p)();
	A* b = &a;
	(b->*p)(); //打印 A
     /*尽管a.p2本身是个非static变量,但是a.p2是指向static函数的函数指针,
     **所以下面这就话是错的!
     */
    //p = a.p2;//error
	void (*pp)(void);
	pp = &A::funb;
	pp(); //打印 B
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值