一、函数指针
函数存放在内存的代码区域内,它们同样有地址.如果我们有一个 int test(int a) 的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。
1、函数指针的定义方式
data_types (*func_pointer)( data_types arg1, data_types arg2, ...,data_types argn);
例如:
int (*fp)(int a); // 这里就定义了一个指向函数(这个函数参数仅仅为一个 int 类型,函数返回值是 int 类型)的指针 fp。
实例
int test(int a)
{
return a;
}
int main(int argc, const char * argv[])
{
int (*fp)(int a);
fp = test;
cout<<fp(2)<<endl;
return 0;
}
注意:函数指针所指向的函数一定要保持函数的返回值类型,函数参数个数,类型一致。
2、typedef 定义可以简化函数指针的定义
实例
int test(int a)
{
return a;
}
int main(int argc, const char * argv[])
{
typedef int (*fp)(int a);
fp f = test;
cout<<f(2)<<endl;
return 0;
}
3、 函数指针同样是可以作为参数传递给函数的
实例
int test(int a)
{
return a-1;
}
int test2(int (*fun)(int),int b)
{
int c = fun(10)+b;
return c;
}
int main(int argc, const char * argv[])
{
typedef int (*fp)(int a);
fp f = test;
cout<<test2(f, 1)<<endl;
return 0;
}
执行以上代码,输出结果为:
10
4、利用函数指针,我们可以构成函数指针数组,更明确点的说法是构成指向函数的指针数组。
实例
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);
fp b[] = {t1,t2,t3};
b[0]();
return 0;
}
二、指向类成员函数的函数指针
定义:类成员函数指针(member function pointer),是 C++ 语言的一类指针数据类型,用于存储一个指定类具有给定的形参列表与返回值类型的成员函数的访问信息。
基本上要注意的有两点:
-
1、函数指针赋值要使用 &
-
2、使用 .* (实例对象)或者 ->*(实例对象指针)调用类成员函数指针所指向的函数
下面看两个例子:
A) 类成员函数指针指向类中的非静态成员函数
对于 nonstatic member function (非静态成员函数)取地址,获得该函数在内存中的实际地址
对于 virtual function(虚函数), 其地址在编译时期是未知的,所以对于 virtual member function(虚成员函数)取其地址,所能获得的只是一个索引值
实例
#include <iostream>
#include <cstdio>
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 printa()
{
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 printa()
{
A::printa();
cout << "B: " << b << endl;
}
private:
int b;
};
int main(void)
{
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::print(): %p\n", &A::printa);
a.print();
a.setA(10);
a.print();
a.setA(100);
a.print();
(pa->*ptr)(1000);
a.print();
(a.*ptr)(10000);
a.print();
return 0;
}
执行以上代码,输出结果为:
A::set(): 0x8048a38
B::print(): 0x1
B::print(): 0x5
A: 0
A: 10
A: 100
A: 1000
A: 10000
B) 类成员函数指针指向类中的静态成员函数
实例
#include <iostream>
using namespace std;
class A{
public:
void (A::*p1)(void);
void (*p2)(void);
A(){
p1 =&A::funa;
p2 =&A::funb;
}
void funa(void){
puts("A");
}
static void funb(void){
puts("B");
}
};
int main()
{
A a;
void (A::*p)(void);
(a.*a.p1)();
p = a.p1;
(a.*p)();
A *b = &a;
(b->*p)();
void (*pp)(void);
pp = &A::funb;
pp();
return 0;
}
总结
类成员函数指针与普通函数指针不是一码事。前者要用 .* 与 ->* 运算符来使用,而后者可以用 * 运算符(称为"解引用"dereference,或称"间址"indirection)。
普通函数指针实际上保存的是函数体的开始地址,因此也称"代码指针",以区别于 C/C++ 最常用的数据指针。
而类成员函数指针就不仅仅是类成员函数的内存起始地址,还需要能解决因为 C++ 的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候一定要传入类实例对象。
原文地址:https://blog.csdn.net/crayondeng/article/details/16868351
点我分享笔记