C++之类成员指针

来源:互联网 发布:工信部大数据认证考试 编辑:程序博客网 时间:2024/06/03 05:14

//

需要用到  .* 和 ->* 两个操作符了。其实这两个操作符也没啥新奇的。. 和 ->分别为对象和对象指针的成员访问操作符, 而 * 则为解引用操作符。当写下 aC.*ipm 时,其实就是请求将 aC的地址加上ipm所表示的偏移量,然后访问该 aC 所表示的对象中的特定数据成员。当写下 pC->*ipm 时,其实就是pC所指向的地址加上ipm所表示的偏移量,然后访问pC所指向的对象中的特定数据成员。

//

一、指向成员变量的指针并非指针

         C++中指向成员变量的指针其实是一个相对于类对象的偏移量。《C++必知必会》的条款15讲述了这一说法:“与常规指针不同,一个指向成员变量的指针并不指向一个内存位置。它指向的是一个类的特定成员,而不是指向一个特定对象里的特定成员。通常最清晰的做法是将指向数据成员的指针看作为一个偏移量。......。这个偏移量告诉你,一个特定成员的位置距离对象的起点有多少个字节。”

看一段示例代码:

[cpp] view plain copy
  1. class DemoClass  
  2. {  
  3. public:  
  4.     DemoClass() : m_a(100) { }  
  5.   
  6.     // ....  
  7.   
  8. public:  
  9.     int m_a;  
  10. };  
  11.   
  12.   
  13. int DemoClass::*ipm = 0; // ipm是一个指针,指向类DemoClass的一个int成员,该处初始化为0  
  14.   
  15.   
  16. void printAddress()  
  17. {  
  18.     DemoClass aC;  
  19.   
  20.     cout << &(aC.m_a) << endl;  // 0x22fecc  
  21.   
  22.     //ipm = &(aC.m_a); // 编译错误: cannot convert 'int*' to 'int DemoClass::*' in assignment  
  23.   
  24.     ipm = &DemoClass::m_a; // ok  
  25.     cout << ipm << endl; // 1 opps! 注意哦!这里输出1,即offset == 1  
  26.   
  27.     cout << aC.m_a << endl;  // 100  
  28.     aC.*ipm = 99; //  这是神马用法? 很惊奇!! O(∩_∩)O哈哈~  
  29.     cout << aC.m_a << endl;  // 99  
  30.   
  31.     DemoClass *pC = &aC;  
  32.     cout << pC->m_a << endl;  // 99  
  33.     pC->*ipm = 1001; //  这又是神马用法? 其实等价于 aC.*ipm = 99; O(∩_∩)O哈哈~  
  34.     cout << aC.m_a << " | " << pC->m_a << " | " << pC->*ipm << endl;  // 1001 | 1001 | 1001  
  35. }  

由其可见,给定一个成员变量在类中的偏移量,为了访问位于那个偏移量的数据成员,我们还需要该类的一个对象的地址。这时候就需要用到  .* 和 ->* 两个操作符了。其实这两个操作符也没啥新奇的。. 和 ->分别为对象和对象指针的成员访问操作符, 而 * 则为解引用操作符。当写下 aC.*ipm 时,其实就是请求将 aC的地址加上ipm所表示的偏移量,然后访问该 aC 所表示的对象中的特定数据成员。当写下 pC->*ipm 时,其实就是pC所指向的地址加上ipm所表示的偏移量,然后访问pC所指向的对象中的特定数据成员。

二、指向成员函数的指针并非指针

      获取非静态成员函数的地址时,得到的不是一个地址,而是一个指向成员函数的指针。为了对一个指向成员函数的指针进行解引用,需要一个对象或一个指向对象的指针。因为通过指向成员函数的指针调用该函数时,需要将对象的地址用作this指针的值,以便进行函数调用(当然,也有其它的用途)。

下面是一段“指向成员函数指针”使用的示例代码:

[cpp] view plain copy
  1. struct Point  
  2. {  
  3.     int x;  
  4.     int y;  
  5. };  
  6.   
  7. class Shape  
  8. {  
  9. public:  
  10.     // ....  
  11.     void moveTo(Point newLocation)  
  12.     {  
  13.         cout << "(" << newLocation.x << ", " << newLocation.y << ")" << endl;  
  14.     }  
  15.     bool validate() const  
  16.     {  
  17.         cout << "Shape::validate()" << endl;  
  18.         return true;  
  19.     }  
  20.     virtual bool draw() const = 0;  
  21.     // ....  
  22. };  
  23.   
  24. class Circle : public Shape  
  25. {  
  26.     // ....  
  27.     virtual bool draw() const  
  28.     {  
  29.         return true;  
  30.     }  
  31.     // ....  
  32. };  
  33.   
  34. void (Shape::*pmf)(Point) = 0;  
  35.   
  36. void testMemberFunctionPointer()  
  37. {  
  38.     pmf = &Shape::moveTo;  
  39.   
  40.     Circle circle;  
  41.   
  42.     //pmf = &circle.moveTo; // 编译错误:ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&Circle::moveTo'  
  43.   
  44.     Point pt;  
  45.     pt.x = 9999;  
  46.     pt.y = 9999;  
  47.     (circle.*pmf)(pt); // 通过对象直接调用 .*  
  48.     pt.x = 888;  
  49.     (&circle->*pmf)(pt);  
  50.   
  51.     Shape *ps = &circle;  
  52.     (ps->*pmf)(pt); // 通过指针调用 ->*  
  53.   
  54.     void (Circle::*pmf2)(Point) = &Shape::moveTo;  
  55.     (circle.*pmf2)(pt);  
  56.     void (Shape::*pmf3)(Point) = &Circle::moveTo;  
  57.     (circle.*pmf3)(pt);  
  58.   
  59.   
  60.     bool (Shape::*pmV)() const = 0;  
  61.     pmV = &Shape::validate;  
  62.     (circle.*pmV)();  
  63. }  


尽管指向类成员(包括成员变量和成员函数)的指针使用很少,但是知道这些概念还是有好处的。

2

0 0
原创粉丝点击