C++成员指针
C++中,成员指针是最为复杂的语法结构。但在事件驱动和多线程应用中被广泛用于调用回叫函数。在多线程应用中,每个线程都通过指向成员函数的指针来调用该函数。在这样的应用中,如果不用成员指针,编程是非常困难的。
刚遇到这种语法时也许会让你止步不前。但你会发现,使用恰当的类型定义之后,复杂的语法是可以简化的。本文引导你了解成员函数指针的声明,赋值和调用回叫函数。
成员函数指针的声明
一个成员函数指针包括成员函数的返回类型,后随::操作符类名,指针名和函数的参数。初看上去,语法有点复杂。其实可以把它理解为一个指向原函数的指针,格式是:函数返回类型,类名,::操作符,指针星号,指针名,函数参数。
一个指向外部函数的指针声明为:
void (*pf)(char *, const char *);
void strcpy(char * dest, const char * source);
pf=strcpy;
一个指向类A成员函数的指针声明为:
void (A::*pmf)(char *, const char *);
声明的解释是:pmf是一个指向A成员函数的指针,返回无类型值,函数带有二个参数,参数的类型分别是char * 和 const char *。除了在星号前增加A:: ,与声明外部函数指针的方法一样。
赋值
给成员指针赋值的方法是将函数名通过指针符号&赋予指针名。如下所示:
class A
{
public:
void strcpy(char *, const char *);
void strcat(char *, const char *);
};
pmf = &A::strcpy;
有些老的编译器可以通过没有&号的赋值方式,但标准C++强制要求加上&号。
使用类型定义
可以用类型定义来隐藏复杂的成员指针语法。例如,下面的语句定义了PMA是一个指向A成员函数的指针,函数返回无类型值,函数参数类型为char * 和 const char *:
typedef void(A::*PMA)(char *, const char *);
PMA pmf= &A::strcat; // pmf是PMF类型(类A成员指针)的变量
下文会看到使用类型定义特别有利于声明成员指针数组。
通过成员指针调用成员函数
可以在不必知道函数名的情况下,通过成员指针调用对象的成员函数。例如,函数dispatcher有一个变量pmf,通过它调用类成员函数,不管它调用的是strcpy()函数还是strcat()函数。指向外部原函数的指针和指向类成员函数的指针是有很大区别的。后者必须指向被调函数的宿主对象。因此,除了要有成员指针外,还要有合法对象或对象指针。
现举例做进一步说明。假设A有二个实例,成员函数指针支持多态性。这样在成员指针调用虚成员函数时是动态处理的(即所谓后联编 - 译注)。注意,不可调用构造和析构函数。示例如下:
A a1, a2;
A *p= &a1; //创建指向A的指针
//创建指向成员的指针并初始化
void (A::*pmf)(char *, const char *) = &A::strcpy;
//要将成员函数绑定到pmf,必须定义呼叫的对象。
//可以用*号引导:
void dispatcher(A a, void (A::*pmf)(char *, const char *))
{
char str[4];
(a.*pmf)(str, “abc”); //将成员函数绑定到pmf
}
//或用A的指针表达方式指向成员指针:
void dispatcher(A * p, void (A::*pmf)(char *, const char *))
{
char str[4]; (p->*pmf)(str, “abc”);
}
//函数的调用方法为:
dispatcher(a, pmf); // .* 方式
dispatcher(&a, pmf); // ->* 方式
高级使用技巧
以上是成员函数的基本知识。现在介绍它的高级使用技巧。
成员指针数组
在下例,声明了一个含有二个成员指针的数组,并分配类的成员函数地址给成员指针:
PMA pmf[2]= {&A::strcpy, &A::strcat};
也就是
void (A::*PMA[2])(char *, const char *)= {&A::strcpy, &A::strcat};
这样的数组在菜单驱动应用中很有用。选择菜单项后,应用将调用相应的回叫函数,如下所示:
enum MENU_OPTIONS { COPY, CONCAT };
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 类型的成员函数
成员指针的类型应该与成员函数类型一致。上面例子中的pmf 可以指向A的任意函数,只要该函数不是const类型。如下所示,如果将touppercase()的地址分配给pmf,将导致编译出错,因为touppercase() 的类型是const。
Class A
{
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; // 现在可以了
有些差劲的编译器允许一个非const类型的成员指针指向const类型的成员函数。这在标准C++是不允许的。
C++成员指针的更多相关文章
- c++_day5_成员指针
1.成员指针实质:特定成员变量在对象实例中的相对地址. 2.类内可以直接初始化静态常量(声明部分).
- C++ Primer 笔记——类成员指针
1.当我们初始化一个成员指针或为成员指针赋值时,该指针并没有指向任何数据.成员指针指定了成员而非成员所属的对象,只有当解引用成员指针时,我们才提供对象信息. 2.和普通的函数指针类似,如果成员存在重载 ...
- C/C++基础----特殊工具和技术 (重载new和delete,RTT,限定作用域的枚举类型,类成员指针,嵌套类,局部类,volatile,链接指示 extern “C”)
重载new和delete 1调用operator new( 或new[])标准库函数分配足够大的.原始的.未命名的内存空间以便存储特定类型的对象 2编译器运行相应地构造函数以构造这些对象,并为其传入初 ...
- C/C++杂记:深入理解数据成员指针、函数成员指针
1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针. 而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始地址的偏移值,空指针用-1表示.例: 代码示例: str ...
- C++中的类成员指针
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- 【转载】C/C++杂记:深入理解数据成员指针、函数成员指针
原文:C/C++杂记:深入理解数据成员指针.函数成员指针 1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针.而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始 ...
- 拷贝构造和拷贝赋值、静态成员(static)、成员指针、操作符重载(day06)
十七 拷贝构造和拷贝赋值 浅拷贝和深拷贝 )如果一个类中包含指针形式的成员变量,缺省的拷贝构造函数只是复制了指针变量的本身,而没有复制指针所指向的内容,这种拷贝方式称为浅拷贝. )浅拷贝将导致不同对象 ...
- 成员指针与mem_fn
本文是<functional>系列的第4篇. 成员指针是一个非常具有C++特色的功能.更低级的语言(如C)没有类,也就没有成员的概念:更高级的语言(如Java)没有指针,即使有也不会有成员 ...
- C++ 类成员指针
C++的类成员指针是一种奇葩的指针. 假设现在我们要表示一个三维的点,现在有两种定义方式: struct point1{ int x, y, z; }; struct point2{ int c[3] ...
随机推荐
- Linux iptables 从入门到放弃
iptables表(iptables)和链(chains) 描述完iptables术语后,相信大家对iptables的表和链有了初步的了解.默认情况下,Iptables根据功能和表的定义划分包含 ...
- Spring与web.xml
出处:http://blog.csdn.net/u010796790 在web.xml配置监听器 ContextLoaderListener (listener-class) ContextLoade ...
- 剑指offer之 奇数偶数数组位置调整且保存顺序不变
public class Solution { public void reOrderArray(int [] array) { reOrderCore(array,array.length); } ...
- PHP中include路径的解决方法汇总
这几天整理一份很乱的代码,这才意识到php对include处理不是一般的贱:别的编程语言在处理include中的相对目录时,都是以当前处理的文件作为基准.也就是说,如果A包含B,B包含C时,C再包含一 ...
- DBGrideh 实现自动排序
一.点击标题自动排序 1.在optioneh中设置:AutosortMarking:=True2.设置DbGridEh的属性:(不一定总要设置,与使用的数据连接有关)sortlocal:=True;3 ...
- mysql基本语句1
操作MySQL数据库 向表中插入数据 insert 语句可以用来将一行或多行数据插到数据库表中, 使用的一般形式如下: insert [into] 表名 [(列名1, 列名2, 列名3, ...)] ...
- Linux_笔记_01_设置静态IP与 SecureCRT连接Linux
步骤一至三,即可设置好静态IP 步骤四至九,使SecureCRT连接Linux 步骤一:编辑ifcfg-eth0 文件 1.打开ifcfg-eth0 文件 使用命令:vi /etc/sysconfig ...
- Post提交和Get提交的区别
表单提交中get和post的区别 1. get: 把表单内各个字段均显示在URL中. post:把表单内各个字段和内容放在html的header内一起传递给action所指的url,用户看不到. 2. ...
- 关于android 图片加载优化
android应用对图片处理算是比较频繁的了,尤其是在程序加载大量图片和高分辨率图片时,最容易产生oom异常,下面是个人平时一些省内存加载方法 方法一: public Bitmap decodeFil ...
- JS上传图片-通过FileReader获取图片的base64
下面文章,我想要的是: FileReader这个对象,可以借助FileReader来获取上传图片的base64,就可以在客户端显示该图片了.同时,还可以把该图片的base64发送到服务端,保存起来. ...