c++ primer笔记27: Pointer to Class Member

1. Pointer to Class Member

A pointer to member embodies the type of the class as well as the type of the member. Pointers to member apply only to non static members of a class. static class members are not part of any object, so no special syntax is needed to point to a static member. Pointers to static members are ordinary pointers.

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;
};
## 2. Defining a Pointer to Data Member
string Screen::*ps_Screen = &Screen::contents;

普通指针使用*来标示,而指向类的成员函数的指针使用ClassName::*标示。需要注意的是,指向类的数据成员的指针并非指针,因为它既不包含地址,行为也不像指针。与常规指针不同,一个指向成员的指针并不指向一个具体的内存位置,它指向的是一个类的特定成员,而不是指向一个特定对象里的特定成员。通常最清晰的做法是将指向数据成员的指针看作 为一个偏移量 。 C++标准并没有说该如何实现指向成员的指针,大多数编译器都将指向数据成员的指针实现为一个整数,其中包含被指向成员的偏移量。另外加上1(加1是为了让0值可以表示一个空的数据成员指针)。 这个偏移量告诉你,一个特定成员的位置距离对象的起点有多少个字节。一个类成员的偏移量在任何对象中都是相同的。 为啥偏移量会加1呢?这主要用来区分“没有指向任何数据成员的指针”和“指向第一个数据成员的指针”这两种情况。考虑下面这样的例子:

float Point3d::*p1 =0;
float Point3d::*p2 = &Point3d::x;

if( p1 == p2 ){
cout <<” p1 & p2 contain the same value.”;
cout <<”they must address the same member!”<<endl;
}

3. Defining a Pointer to Member Function

A pointer to a member function must match the type of the function to which it points, in three ways:

  • The type and number of the function parameters, including whether the member is const.
  • The return type.
  • The class type of which it is a member
    char (Screen::*pmf)() const = &Screen::get;

    char (Screen::*pmf2)(Screen::index, Screen::index) const;
    pmf2 = &Screen::get;

    typedef char (Screen::*Action)(Screen::index, Screen::index) const;
    Action get = &Screen::get;

4. Using a Pointer to Member Function

char (Screen::*pmf)() const = &Screen::get;
Screen myScreen;
char c1 = myScreen.get(); // call get on myScreen
char c2 = (myScreen.*pmf)(); // equivalent call to get
Screen *pScreen = &myScreen;
c1 = pScreen->get(); // call get on object to which pScreen points
c2 = (pScreen->*pmf)(); // equivalent call to get

5. Using a Pointer to Data Member

Screen::index Screen::*pindex = &Screen::width;
Screen myScreen;
// equivalent ways to fetch width member of myScreen
Screen::index ind1 = myScreen.width; // directly
Screen::index ind2 = myScreen.*pindex; // dereference to get width
Screen *pScreen;
// equivalent ways to fetch width member of *pScreen
ind1 = pScreen->width; // directly
ind2 = pScreen->*pindex; // dereference pindex to get width

6. Pointer-to-Member Function Tables

One common use for function pointers and for pointers to member functions is to store them in a function table. A function table is a collection of function pointers from which a given call is selected at run time.

class Screen {
public:
// other interface and implementation members as before
Screen& home(); // cursor movement functions
Screen& forward();
Screen& back();
Screen& up();
Screen& down();
};

class Screen {
public:
// other interface and implementation members as before
// Action is pointer that can be assigned any of the cursor movement members
typedef Screen& (Screen::*Action)();
static Action Menu[]; // function table
public:
// specify which direction to move
enum Directions { HOME, FORWARD, BACK, UP, DOWN };
Screen& move(Directions);
};

Screen& Screen::move(Directions cm)
{
// fetch the element in Menu indexed by cm
// run that member on behalf of this object
(this->*Menu[cm])();
return *this;
}

// What's left is to define and initialize the table itself:
Screen::Action Screen::Menu[] = { &Screen::home,
&Screen::forward,
&Screen::back,
&Screen::up,
&Screen::down,
};

Screen myScreen;
myScreen.move(Screen::HOME); // invokes myScreen.home
myScreen.move(Screen::DOWN); // invokes myScreen.down