现在的位置: 首页 > 综合 > 正文

C++ Primer学习笔记——$22 类成员指针

2018年03月30日 ⁄ 综合 ⁄ 共 3405字 ⁄ 字号 评论关闭

题记:本系列学习笔记(C++ Primer学习笔记)主要目的是讨论一些容易被大家忽略或者容易形成错误认识的内容。只适合于有了一定的C++基础的读者(至少学完一本C++教程)。

 
作者: tyc611, 2007-04-07


   本文主要讨论C++中类成员的指针,这部分内容少有使用,也比较难于理解。
   如果文中有错误或遗漏之处,敬请指出,谢谢!


   需要使用类成员指针的情况是比较少见的,所以一般没人使用这个语言特性。下面先介绍类成员指针的使用方法,再介绍它的可能应用场合。
 
   有时,我们需要在类外的其它地方直接获得类成员,这时我们就需要使用类成员指针。类成员指针与对象的指针不同,它不仅包括类的类型,还包括成员的类型。成员指针只应用于类的非static成员,因为static类成员不是任何对象的组成部分,只需使用普通指针即可。
 
声明成员指针
 
   借用书上的一个例子,有这么一个类:
   class Screen {
   public:
      typedef std::string::size_type index;
      char get() const;
      char get(index ht, index wd) const;
   private:
      std::string contents;
      index cursor;
      index height, width;
   };
  
   若要声明contents成员的指针,应有如下形式:
      string Screen::*ps;
   若要声明cursor、height或width成员的指针,应有如下形式:
      Screen::index Screen::*pi;
 
   从上面的使用形式可以看出,使用类成员的指针与普通指针的区别在于,需要在类成员指针前面的加上类限定符,以指明是哪个类的成员指针。同样,在初始化指针时,也只能用相应类的相应类型的成员对指针进行初始化,例如:
      ps = &Screen::contents;
      pi = &Screen::cursor;
 
   上面介绍了对类数据成员的指针的使用方法,下面对函数成员的指针进行介绍。
 
   函数成员的指针与普通函数指针相比,也多了类限定符。由于类成员函数还有可能是const,所以const也成为成员函数指针声明的一部分。也就是说,函数成员的指针必须在三个方面与它所指函数的类型相匹配:
   (1)函数形参的类型和数目;
   (2)返回类型及是否为const函数;
   (3)所属类的类型。
 
   例如,要定义Screen的get成员的指针,可以如下定义:
      char (Screen::*pmf)() const = &Screen::get; // not 'Screen::get'!
      char (Screen::*pmf2)(Screen::index, Screen::index) const;
      pmf2 = &Screen::get;
这里需要注意的是:(1)这里不存在函数类型到函数指针类型的自动转换(即类成员函数前面必须加上&,然后再给相应指针赋值);(2)运算符的优先级关系(注意指针外层的括号所起的作用);(3)函数到指针的自动类型匹配(注意两个重载版本的get对指针的赋值)。
 
使用类成员指针
 
   要使用类成员指针所指对象,首先应当从类对象取得成员指针,再解引用指针,所以有如下两种操作符供使用:.*和->*。这两个操作符的左操作数必须是类类型的对象或类类型的指针,右操作数是该类型的成员指针。例如:
   Screen sc;
   char c = (sc.*pmf)();  // 等价于调用sc.get();
   Screen *pS = ≻
   c = (pS->*pmf)();
 
   下面给出成员指针使用的完整例子,以方便读者更好的理解:

#include <string>

class Screen {
    friend void func(); // 声明func为类Screen的友元,否则无法使用类成员
public:
    typedef std::string::size_type index;
    char get() const {
        return 'a';
    }
    char get(index ht, index wd) const {
        return 'b';
    }
private:
    std::string contents;
    index cursor;
    index heigth, width;
};

void func()
{
    std::string Screen:: *ps = &Screen::contents;
    Screen::index Screen:: *pi = &Screen::cursor;
    char (Screen:: *pmf) () const = &Screen::get; // not 'Screen::get'!
    char (Screen:: *pmf2) (Screen::index, Screen::index) const;
    pmf2 = &Screen::get;
    
    Screen sc;
    Screen *pS = &sc;
    Screen::index idx = sc.*pi;
    idx = pS->*pi;
    char c = (sc.*pmf)();
// 等价于调用sc.get();
    c = (pS->*pmf)();
}

int main()
{
    void (*pf)() = func// 注意普通函数的指针的初始化,与成员指针比较
    pf();
    return 0;
}

 
成员指针的应用举例
 
   当一个类有多个性质相同且类型相同的函数成员时,可以使用函数表来进行函数调用,产生用同一函数使用不同参数来达到不同操作的效果,而实际上是调用了不同的函数来实现的。下面给出这样的一个例子,方便读者有一个感性的认识:

#include <iostream>
using namespace std;

class Screen {
public:
    Screen& home() {
        cout << "Home" << endl;
        return *this;
    }
    Screen& forward() {
        cout << "Forward" << endl;
        return *this;
    }
    Screen& back() {
        cout << "Back" << endl;
        return *this;
    }
    Screen& up() {
        cout << "Up" << endl;
        return *this;
    }
    Screen& down() {
        cout << "down" << endl;
        return *this;
    }
    // function table
    typedef Screen& (Screen:: *Action)();
    static Action Menu[];
    
// specify which direction to move
    enum Directions {HOME, FORWARD, BACK, UP, DOWN};
    Screen& move(Directions);
};

Screen::Action Screen::Menu[] = {&Screen::home, &Screen::forward, &Screen::back, &Screen::up, &Screen::down};

Screen& Screen::move(Directions dirc)
{
    (this->*Menu[dirc])();
    return *this;
}

int main()
{
    Screen sc;
    sc.move(Screen::HOME);
    sc.move(Screen::UP);
    return 0;
}

 

参考文献:
[1] C++ Primer(Edition 4)
[2] Thinking in C++(Edition 2)
[3] International Standard:ISO/IEC 14882:1998

抱歉!评论已关闭.