函数指针
函数指针就是指向函数的指针,它与普通指针类型一样,所占内存为4字节(32位系统)。不同的是,它存储的是函数的地址而非数据地址。
//有两个参数,分别是char*和int且返回值是int的函数指针
int (*pFunc)(char*, int);
//无参数且返回类型是整型的函数指针
int (*somefunction)();
//有两个整型参数且返回值是bool的函数指针
把一个函数赋给一个函数指针
int foo()
{
return 5;
}
int goo()
{
return 6;
}
int main()
{
int (*funcPtr)() = foo; // funcPtr 现在指向了函数foo
funcPtr = goo; // funcPtr 现在又指向了函数goo
return 0;
}
funcPtr = goo()//;这是把goo的返回值赋值给了funcPtr
类成员函数指针
顾名思义就是类中的成员函数的函数指针
要注意两点:
1.函数指针复制要使用&
2.使用 .* (实例对象)或者 ->*(实例对象指针)调用类成员函数指针所指向的函数
一.类成员函数指针指向类中的非静态成员函数
对于非静态成员函数取地址,获得该函数在内存中的实际地址
对于虚函数, 其地址在编译时期是未知的,所以对于虚成员函数取其地址,所能获得的只是一个索引值,这个索引值是该虚函数在虚函数表的偏移位置
对于指向非静态的类成员函数的函数指针,引用时必须传入一个类对象的this指针,所以必须由类实体调用。
当类成员函数声明为静态的,函数与类的任何特定对象相对独立。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问,不需要通过类实例对象调用。
静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。
//指向类成员函数的函数指针
#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();
//对于指向类成员函数的函数指针,引用时必须传入一个类对象的this指针,所以必须由类实体调用
(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
二.类成员函数指针指向类的静态成员函数
#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()
{
A a;
//p是指向A中非static成员函数的函数指针
void (A::*p)(void);
(a.*a.p1)(); //打印 A
//使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数
p = a.p1;
(a.*p)();//打印 A
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;
}
类成员函数指针与普通函数指针不是一码事。前者要用 .* 与 ->* 运算符来使用,而后者可以用 * 运算符(称为”解引用”dereference,或称”间址”indirection)。
普通函数指针实际上保存的是函数体的开始地址,因此也称”代码指针”,以区别于 C/C++ 最常用的数据指针。
而类成员函数指针就不仅仅是类成员函数的内存起始地址,还需要能解决因为 C++ 的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候一定要传入类实例对象。
今天的文章C++学习–函数指针和类成员函数指针「建议收藏」分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/79907.html