C++学习笔记(四)--指针(4)

 

类成员指针

 

 


   本文主要讨论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;

   若要声明cursorheightwidth成员的指针,应有如下形式:

      Screen::index Screen::*pi;

 

   从上面的使用形式可以看出,使用类成员的指针与普通指针的区别在于,需要在类成员指针前面的加上类限定符,以指明是哪个类的成员指针。同样,在初始化指针时,也只能用相应类的相应类型的成员对指针进行初始化,例如:

      ps = &Screen::contents;

      pi = &Screen::cursor;

 

   上面介绍了对类数据成员的指针的使用方法,下面对函数成员的指针进行介绍。

 

   函数成员的指针与普通函数指针相比,也多了类限定符。由于类成员函数还有可能是const,所以const也成为成员函数指针声明的一部分。也就是说,函数成员的指针必须在三个方面与它所指函数的类型相匹配:

   1)函数形参的类型和数目;

   2)返回类型及是否为const函数;

   3)所属类的类型。

 

   例如,要定义Screenget成员的指针,可以如下定义:

      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

 

源文档 <http://blog.chinaunix.net/u/18517/showart_272646.html>

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值