指向类成员的指针

指向类成员的指针,印象中似乎很少用到,重新学习C++的过程中,才发现自己是忽视了一个很重要的东东,以前我一直认为类的成员函数不能作为回调函数,所以很多C程序都始终无法移植到C++上来,现在才知道,这是对指向类成员的指针不了解的缘故。


1、指向非静态成员的指针

其实指向非静态的类成员的指针很容易,它们与普通指针唯一的区别是,他们受类的限制。如下:

class A

{

int _val;

int val();

};

int (A::p_val) = &A::_val;

int ( A::
p_func )() = &A::val;

看到了吗,是的,和普通的指针的区别是,指向类成员的指针必须把类也一并带上,上面的例子中就是要把A::这个限定符一起戴上,然后?用法和普通指针一样的就是了。


2、指向静态成员的指针

指向静态成员的指针,声明的方式和普通指针完全一样,只是赋值的时候,还得加上类的限定符。为什么这样?我想可以这样来理解,对于非静态成员,其存在取决于类,类消亡的时候,非静态成员随之消亡,所以,其声明必须与类的限定符绑在一起,而静态成员对于类而言并无依附关系,所以,不需要类的限定符。如下:

class A

{

static int _val;

static int val();

};

int p_val = &A::_val;

int (
p_func)() = &A::val;



3、好处:

一个好处是,通过指向成员的函数指针,可以很轻松的调用各个成员函数了;另一个好处是,对于静态成员函数,可以成为C里的回调函数啦。



下面是一个例子,加深一下理解:

#include

#include



using namespace std;



typedef void (funchandler)();



void register_func(funchandler f)

{

cout << "register_func" << endl;

(
f)();

}



class A

{

public:

A() : _val( 0 ) { cout << "create A..." << endl; }

void test() { cout << "test..." << endl; }

void test1() { cout << "test1..." << endl; }

void test2() { cout << "test2..." << endl; }

int val() { return _val; }

static void test3() { cout << "test3..." << endl; }

int _val;

private:

};







int main()

{

A a;

int ( A::p_val ) = 0;

p_val = &A::_val;

cout << "a.
p_val: " << a.p_val << endl;



void (A::
p_func)();

p_func = &A::test;



a.test();

(a.p_func)();



p_func = &A::test1;

( a.
p_func )();

p_func = &A::test2;

( a.p_func )();



void (
pp_func)();

pp_func = &A::test3;

(*pp_func)();



register_func( pp_func );

return 0;

}

通过成员指针调用成员函数



可以在不必知道函数名的情况下,通过成员指针调用对象的成员函数。例如,函数dispatcher有一个变量pmf,通过它调用类成员函数,不管它调用的是strcpy()函数还是strcat()函数。指向外部原函数的指针和指向类成员函数的指针是有很大区别的。后者必须指向被调函数的宿主对象。因此,除了要有成员指针外,还要有合法对象或对象指针。



现举例做进一步说明。假设A有二个实例,成员函数指针支持多态性。这样在成员指针调用虚成员函数时是动态处理的(即所谓后联编 - 译注)。注意,不可调用构造和析构函数。示例如下:




A a1, a2;



A
p=&a1;//创建指向A的指针



//创建指向成员的指针并初始化



void(A::
pmf)(char,constchar)=&A::strcpy;



//要将成员函数绑定到pmf,必须定义呼叫的对象。



//可以用号引导:



voiddispatcher(Aa,void(A::
pmf)(char,constchar))



{



charstr[4];



(a.
pmf)(str, “abc”);//将成员函数绑定到pmf



}



//或用A的指针表达方式指向成员指针:



voiddispatcher(A
p,void(A::pmf)(char,constchar))



{



charstr[4]; (p->
pmf)(str, “abc”);



}



//函数的调用方法为:



dispatcher(a, pmf);
//. 方式



dispatcher(
&a, pmf);//->
方式

成员指针数组

classA

{



public:



voidstrcpy(char,constchar);



voidstrcat(char,constchar);



};


在下例,声明了一个含有二个成员指针的数组,并分配类的成员函数地址给成员指针:

typedef void(A::PMA)(char , const char );



PMA pmf[2]= {&A::strcpy, &A::strcat};

也就是

void (A::
PMA[2])(char , const char )= {&A::strcpy, &A::strcat};



这样的数组在菜单驱动应用中很有用。选择菜单项后,应用将调用相应的回叫函数,如下所示:




enumMENU_OPTIONS { COPY, CONCAT };



intmain()

{

MENU_OPTIONS option;
charstr[4];

//从外部资源读取选项

switch(option)

{

caseCOPY:



(pa
->pmf[COPY])(str, “abc”);



break;



caseCONCAT:



(pa
->
pmf[CONCAT])(str, “abc”);



break;



//



}

}



Const 类型的成员函数



成员指针的类型应该与成员函数类型一致。上面例子中的pmf 可以指向A的任意函数,只要该函数不是const类型。如下所示,如果将touppercase()的地址分配给pmf,将导致编译出错,因为touppercase() 的类型是const。




Class A

{



public:



voidstrpcy(char,constchar);



voidstrcat(char,constchar);



voidtouppercase(char,constchar)const;



};



pmf
=&A::touppercase;//出错,类型不匹配



//解决的方法是声明一个const类型的成员指针:



void(A::pcmf)(char,constchar)const;



pcmf
=&A::touppercase;//现在可以了




有些差劲的编译器允许一个非const类型的成员指针指向const类型的成员函数。这在标准C++是不允许的。
原文链接: https://www.cnblogs.com/weiqubo/archive/2011/03/22/1991364.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/22660

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 上午12:39
下一篇 2023年2月8日 上午12:40

相关推荐