指向类成员的指针
指向類成員的指針,印象中似乎很少用到,重新學(xué)習(xí)C++的過程中,才發(fā)現(xiàn)自己是忽視了一個很重要的東東,以前我一直認(rèn)為類的成員函數(shù)不能作為回調(diào)函數(shù),所以很多C程序都始終無法移植到C++上來,現(xiàn)在才知道,這是對指向類成員的指針不了解的緣故。
1、指向非靜態(tài)成員的指針
其實指向非靜態(tài)的類成員的指針很容易,它們與普通指針唯一的區(qū)別是,他們受類的限制。如下:
class A
{
int _val;
int val();
};
int (A::*p_val) = &A::_val;
int ( A::*p_func )() = &A::val;
看到了嗎,是的,和普通的指針的區(qū)別是,指向類成員的指針必須把類也一并帶上,上面的例子中就是要把A::這個限定符一起戴上,然后?用法和普通指針一樣的就是了。
2、指向靜態(tài)成員的指針
指向靜態(tài)成員的指針,聲明的方式和普通指針完全一樣,只是賦值的時候,還得加上類的限定符。為什么這樣?我想可以這樣來理解,對于非靜態(tài)成員,其存在取決于類,類消亡的時候,非靜態(tài)成員隨之消亡,所以,其聲明必須與類的限定符綁在一起,而靜態(tài)成員對于類而言并無依附關(guān)系,所以,不需要類的限定符。如下:
class A
{
static int _val;
static int val();
};
int *p_val = &A::_val;
int (*p_func)() = &A::val;
3、好處:
一個好處是,通過指向成員的函數(shù)指針,可以很輕松的調(diào)用各個成員函數(shù)了;另一個好處是,對于靜態(tài)成員函數(shù),可以成為C里的回調(diào)函數(shù)啦。
下面是一個例子,加深一下理解:
#include <iostream>
#include <string>
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;
}
?
通過成員指針調(diào)用成員函數(shù)
可以在不必知道函數(shù)名的情況下,通過成員指針調(diào)用對象的成員函數(shù)。例如,函數(shù)dispatcher有一個變量pmf,通過它調(diào)用類成員函數(shù),不管它調(diào)用的是strcpy()函數(shù)還是strcat()函數(shù)。指向外部原函數(shù)的指針和指向類成員函數(shù)的指針是有很大區(qū)別的。后者必須指向被調(diào)函數(shù)的宿主對象。因此,除了要有成員指針外,還要有合法對象或?qū)ο笾羔槨?
現(xiàn)舉例做進(jìn)一步說明。假設(shè)A有二個實例,成員函數(shù)指針支持多態(tài)性。這樣在成員指針調(diào)用虛成員函數(shù)時是動態(tài)處理的(即所謂后聯(lián)編 - 譯注)。注意,不可調(diào)用構(gòu)造和析構(gòu)函數(shù)。示例如下:
A?*p=?&a1;?//創(chuàng)建指向A的指針
//創(chuàng)建指向成員的指針并初始化
void?(A::*pmf)(char?*,?const?char?*)?=?&A::strcpy;
//要將成員函數(shù)綁定到pmf,必須定義呼叫的對象。
//可以用*號引導(dǎo):
void?dispatcher(A?a,?void?(A::*pmf)(char?*,?const?char?*))
{
char?str[4];
(a.*pmf)(str,?“abc”);?//將成員函數(shù)綁定到pmf
}
//或用A的指針表達(dá)方式指向成員指針:
void?dispatcher(A?*?p,?void?(A::*pmf)(char?*,?const?char?*))
{
char?str[4];?(p->*pmf)(str,?“abc”);
}
//函數(shù)的調(diào)用方法為:
dispatcher(a,?pmf);?//?.*?方式
dispatcher(&a,?pmf);?//?->*?方式?
?
成員指針數(shù)組
class?A
{
public:
void?strcpy(char?*,?const?char?*);
void?strcat(char?*,?const?char?*);
};
在下例,聲明了一個含有二個成員指針的數(shù)組,并分配類的成員函數(shù)地址給成員指針:
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};
這樣的數(shù)組在菜單驅(qū)動應(yīng)用中很有用。選擇菜單項后,應(yīng)用將調(diào)用相應(yīng)的回叫函數(shù),如下所示:
int?main()
{
MENU_OPTIONS?option;?char?str[4];
//從外部資源讀取選項
switch?(option)
{
case?COPY:
(pa->*pmf[COPY])(str,?“abc”);
break;
case?CONCAT:
(pa->*pmf[CONCAT])(str,?“abc”);
break;
//…
}
}?
?
Const 類型的成員函數(shù)
成員指針的類型應(yīng)該與成員函數(shù)類型一致。上面例子中的pmf 可以指向A的任意函數(shù),只要該函數(shù)不是const類型。如下所示,如果將touppercase()的地址分配給pmf,將導(dǎo)致編譯出錯,因為touppercase() 的類型是const。
{
public:
? void?strpcy(char?*,?const?char?*);
? void?strcat(char?*,?const?char?*);
? void?touppercase(char?*,?const?char*)?const;
};
pmf=&A::touppercase;?//出錯,類型不匹配
//解決的方法是聲明一個const類型的成員指針:
void?(A::pcmf)(char?*,?const?char?*)?const;
pcmf=&A::touppercase;?//?現(xiàn)在可以了?
有些差勁的編譯器允許一個非const類型的成員指針指向const類型的成員函數(shù)。這在標(biāo)準(zhǔn)C++是不允許的。
轉(zhuǎn)載于:https://www.cnblogs.com/weiqubo/archive/2011/03/22/1991364.html
總結(jié)
- 上一篇: 可乐猪为什么叫可乐猪?
- 下一篇: PHP程序员应该掌握的10项技能