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

转载 2011年01月19日 15:16:00

题记:本系列学习笔记(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

c++ Primer学习笔记

第一章 文件头及声明 关于extern 使用extern 声明而不定义,它是说明变量定义在程序其他地方   全局不初始化的extern int i; 是声明不定义;只要声明并且有初始化式,那么...
  • leiming32
  • leiming32
  • 2012年12月17日 23:57
  • 5216

C++类成员指针的意义

C++中,成员指针是最为复杂的语法结构。但在事件驱动和多线程应用中被广泛用于调用回叫函数。在多线程应用中,每个线程都通过指向成员函数的指针来调用该函数。在这样的应用中,如果不用成员指针,编程是非常困难...
  • captain_wangnb
  • captain_wangnb
  • 2016年01月12日 16:54
  • 1179

C++ Primer 学习笔记(持续更新......)

本笔记主要是一个记录,整理和总结一下C++学习过程中的知识点。 struct和class 区别:两个关键字都是进行类的定义。struct也可以定义类,和class定义的类唯一不同之处就在于默认的初始访...
  • u012931582
  • u012931582
  • 2017年03月12日 22:05
  • 616

C++的类成员指针的语法

C++的类成员指针的语法
  • aflyeaglenku
  • aflyeaglenku
  • 2017年07月15日 15:56
  • 390

《C++ Primer Plus》学习笔记1

C++ Primer Plus》学习笔记1 第二章、开始学习C++ 1、控制符endl 如果显示字符串时,在字符串中包含换行符,而不是在末尾加上endl,这样可以大大减少输入量;如果是要生成...
  • u010555622
  • u010555622
  • 2014年07月15日 01:00
  • 1285

C++ Primer学习笔记(10)——如何读写文件

我们常接触的 cin cout是从控制窗口读写数据,往往是从键盘输入、显示到显示器上,是交互的方式之一。然而,通常还需要读或者写已命名的文件;以及访问内存中的数据。那么C++如何读写文件?...
  • zhangyumumu
  • zhangyumumu
  • 2015年07月05日 10:27
  • 314

C++ Primer(第五版) 学习笔记

C++语言基础: 1. C++11增加了long long 类型,表示最小尺寸为64的整数。 2. 浮点数运算使用double,通常运算速度更快。 3. 超过int容量时使用long long类型,无...
  • zxh2075
  • zxh2075
  • 2016年10月25日 15:56
  • 468

C++primer第五版第一章学习笔记

1. 函数的定义: return type, function name, parameter list, function body // int为返回类型,main为函数名,小括号包围的是可以为...
  • sunhero2010
  • sunhero2010
  • 2015年11月03日 15:30
  • 523

C++ Primer 学习笔记(第一章)

第一章  开始 1.1 编写一个简单的C++程序 1.类型、变量和对象的概念 int是一个整型,其实就是“类型”,也就是“类”,系统定义好的。 OpenCV中的Mat型,也是一种类型,也是类。...
  • Zlase
  • Zlase
  • 2017年10月25日 00:30
  • 91

C++ Primer 学习笔记之 --- 学习总结

vector v1(10); //v1 有10个元素,每个值为0 vector v2{10}; //v2 有1个元素,每个值为10 vector v3(10,1); //v1 有10个元素,每个值...
  • xue_huashan
  • xue_huashan
  • 2016年06月21日 14:10
  • 246
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ Primer学习笔记——$22 类成员指针
举报原因:
原因补充:

(最多只允许输入30个字)