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++强制要求加上&号。 

  使用类型定义 
  

  C++新标准规定了一种新的方法,使用别名声明来定义类型的别名:

  using SI=Sales_item; //SI是Sales_item的同义词

  

  这种使用关键字using作为别名声明的开始,其后紧跟别名和等号,其作用是把等号左侧的名字规定成等号右侧类型的别名。

 

  类型别名和类型的名字等价,只要是类型的名字能出现的地方,就能使用类型别名。

  

  eg: SI item;  //等价于Sales_item item;

  可以用类型定义来隐藏复杂的成员指针语法。例如,下面的语句定义了PMA是一个指向A成员函数的指针,函数返回无类型值,函数参数类型为char
* 和 const char *: 

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

  

  using PMA=void (A::*)(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++成员函数指针的应用,布布扣,bubuko.com

时间: 2024-10-25 18:17:51

C++成员函数指针的应用的相关文章

C++成员函数指针错误用法警示(成员函数指针与高性能的C++委托,三篇),附好多评论

今天做一个成绩管理系统的并发引擎,用Qt做的,仿照QtConcurrent搞了个模板基类.这里为了隐藏细节,隔离变化,把并发的东西全部包含在模板基类中.子类只需注册需要并发执行的入口函数即可在单独线程中执行.最终目标是,继承的业务逻辑类外部调用时有两个接口可选,调用syncRun同步执行:调用由引擎自动生成的asyncRun就异步执行.最终自动生成asyncRun的模板基类没能实现,主要原因是mingw对this处理的太有问题了!!原本以为编译器问题,后来才知道成员函数指针和this指针如此特殊

成员函数指针和指向静态成员函数的指针

#include <iostream> using namespace std; class Student{ public:     Student(const string& name):m_name(name){}     void who(void){         cout << m_name << endl;     }     string m_name;     static int s_add(int a,int b){         re

C++ 指向成员函数指针问题

成员函数指针与常规指针不同,一个指向成员变量的指针并不指向一个内存位置.通常最清晰的做法是将指向数据成员的指针看作为一个偏移量. class ru_m { public: typedef int (ru_m::*p)(); p get_m(); int show(); }; int ru_m::show(){ return 10000; } ru_m::p ru_m::get_m(){ ru_m::p vc; //错误,当为对象时,对象指向的地址为相对地址,非内存地址 //所以,ru_m->sh

为什么 C++ 中成员函数指针是 16 字节?

当我们讨论指针时,通常假设它是一种可以用 void * 指针来表示的东西,在 x86_64 平台下是 8 个字节大小.例如,下面是来自 维基百科中关于 x86_64 的文章 的摘录: Pushes and pops on the stack are always in 8-byte strides, and pointers are 8 bytes wide. 从 CPU 的角度来看,指针无非就是内存的地址,所有的内存地址在 x86_64 平台下都是由 64 位来表示,所以假设它是 8 个字节是

一个完整的使用成员函数指针的例子

Screen.h #ifndef SCREEN_H #define SCREEN_H #include <string> class Screen { public: typedef std::string::size_type pos; // Action is a type that can point to a member function of Screen // that returns a reference to a Screen and takes no arguments

类的成员函数指针和mem_fun适配器的用法

先来看一个最简单的函数: void foo(int a) { cout << a << endl; } 它的函数指针类型为 void (*)(int); 我们可以这样使用: void (*pFunc)(int) = &foo; pFunc(123); 这就是函数指针的基本使用.   类的成员函数   那么,对于类的成员函数,函数指针有什么不同呢? 我们观察下面的类: class Foo { public: //void (Foo::*)(int) void foo(int

自制反汇编工具使用实例 其二(使用xmm寄存器初始化对象,以及空的成员函数指针)

在反汇编代码中,当看到xmm寄存器,第一反应是将要进行浮点操作或访问,但是更加多的情况是在使用xmm寄存器初始化局部对象. 下面是自制反汇编工具翻译出来的代码: // -[CALayer setAllowsEdgeAntialiasing:] void CALayer20_setAllowsEdgeAntialiasing3A_(id self, SEL sel, uintptr_t setAllowsEdgeAntialiasing) { // 0 pushq %rbp // 1 rbp =

成员函数指针,动态绑定(vc平台)

上一篇介绍了gcc对成员函数指针做了thunk的处理,本篇介绍vc对成员函数指针如何处理,还有动态绑定相关的处理. 同样用回上一篇的例子: struct point {float x,y;}; struct obj { virtual ~obj {} void foo(int) {} void foo(point) {} virtual void vfoo() {} }; struct objobj : public obj { virtual ~objobj {} virtual void v

C++的类成员和类成员函数指针

类成员函数指针: 用于访问类成员函数,和一般函数指针有区别. 类成员函数处理的是类数据成员,声明类成员函数指针的同时,还要指出具体是哪个类的函数指针才可以.调用时也要通过对象调用. 而对于类的静态成员函数,它是类对象共享的,且只能处理静态数据成员,所以它的函数指针可以类似一般函数指针一样使用. 1 class Test 2 { 3 public: 4 void fun(int); 5 void fun(int) const; //重载函数,加一个const限制 6 static void fun