18.3. Pointer to Class Member18.3. 类成员的指针We know that, given a pointer to an object, we can fetch a given member from that object using the arrow (->) operator. Sometimes it is useful to start from the member. That is, we may want to obtain a pointer to a specific member and then fetch that member from one or another object. 我们知道,给定对象的指针,可以使用箭头(->)操作符从该对象获得给定成员。有时从成员开始是有用的,也就是说,我们也许希望获得特定成员的指针,然后从一个对象或别的对象获得该成员。 We can do so by using a special kind of pointer known as a pointer to member. A pointer to member embodies the type of the class as well as the type of the member. This fact impacts how pointers to member are defined, how they are bound to a function or data member, and how they are used. 可以通过使用称为成员指针的特殊各类的指针做到这一点。成员指针包含类的类型以及成员的类型。这一事实影响着怎样定义成员指针,怎样将成员指针绑定到函数或数据成员,以及怎样使用它们。 Pointers to member apply only to nonstatic 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. 成员指针只应用于类的非 static 成员。static 类成员不是任何对象的组成部分,所以不需要特殊语法来指向 static 成员,static 成员指针是普通指针。 18.3.1. Declaring a Pointer to Member18.3.1. 声明成员指针In exploring pointers to members, we'll use a simplified version of the Screen class from Chapter 12. 在研究成员指针时,将使用第十二章的 Screen 类的简化版本。 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; }; Defining a Pointer to Data Member定义数据成员的指针The contents member of Screen has type std::string. The complete type of contents is "member of class Screen, whose type is std::string." Consequently, the complete type of a pointer that could point to contents is "pointer to member of class Screen of type std::string." This type is written as Screen 类的 contents 成员的类型为 std::string。contents 的完全类型是“Screen 类的成员,其类型是 std::string”。因此,可以指向 contents 的指针的完全类型是“指向 std::string 类型的 Screen 类成员的指针”,这个类型可写为 string Screen::* We can define a pointer to a string member of class Screen as 可以将指向 Screen 类的 string 成员的指针定义为 string Screen::*ps_Screen; ps_Screen could be initialized with the address of contents by writing 可以用 contents 的地址初始化 ps_Screen,代码为 string Screen::*ps_Screen = &Screen::contents; We could also define a pointer that might address the height, width, or cursor members as 还可以将指向 height、width 或 cursor 成员的指针定义为 Screen::index Screen::*pindex; which says that pindex is a pointer to a member of class Screen with type Screen::index. We could assign the address of width to this pointer as follows: 这是说,pindex 是具有 Screen::index 类型的 Screen 类成员的指针。可以将 width 的地址赋给这个指针: pindex = &Screen::width; The pointer pindex can be set to any of width, height, or cursor because all three are Screen class data members of type index. 可以用指针 pindex 指向 width、height 或 cursor 中任意一个,因为这三个都是 index 类型的 Screen 类成员。 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: 成员函数的指针必须在三个方面与它所指函数的类型相匹配:
A pointer to member function is defined by specifying the function return type, parameter list, and a class. For example, a pointer to a Screen member function capable of referring to the version of get that takes no parameters has the following type: 通过指定函数返回类型、形参表和类来定义成员函数的指针。例如,可引用不接受形参的 get 版本的 Screen 成员函数的指针具有如下类型: char (Screen::*)() const This type specifies a pointer to a const member function of class Screen, taking no parameters and returning a value of type char. A pointer to this version of get can be defined and initialized as follows: 这个类型指定 Screen 类的 const 成员函数的指针,不接受形参并返回 char 类型的值。这个 get 函数版本的指针可以像下面这样定义和初始化: // pmf points to the Screen get member that takes no arguments char (Screen::*pmf)() const = &Screen::get; We might also define a pointer to the two-parameter version of get as 也可以将带两个形参的 get 函数版本的指针定义为 char (Screen::*pmf2)(Screen::index, Screen::index) const; pmf2 = &Screen::get;
// error: non-member function p cannot have const qualifier char Screen::*p() const; Using Typedefs for Member Pointers为成员指针使用类型别名Typedefs can make pointers to members easier to read. For example, the following typedef defines Action to be an alternative name for the type of the two-parameter version of get: 类型别名可以使成员指针更容易阅读。例如,下面的类型别名将 Action 定义为带两个形参的 get 函数版本的类型的另一名字: // Action is a type name typedef char (Screen::*Action)(Screen::index, Screen::index) const; Action is the name of the type "pointer to a const member function of class Screen taking two parameters of type index and returning char." Using the typedef, we can simplify the definition of a pointer to get as follows: Action 是类型“Screen 类的接受两个 index 类型形参并返回 char 的成员函数的指针”的名字。使用类型别名,可以将 get 指针的定义简化为 Action get = &Screen::get; A pointer-to-member function type may be used to declare function parameters and function return types: 可以使用成员指针函数类型来声明函数形参和函数返回类型: // action takes a reference to a Screen and a pointer to Screen member function Screen& action(Screen&, Action = &Screen::get); This function is declared as taking two parameters: a reference to a Screen object and a pointer to a member function of class Screen taking two index parameters and returning a char. We could call action either by passing it a pointer or the address of an appropriate member function in Screen: 这个函数声明为接受两个形参:Screen 对象的引用,以及 Screen 类的接受两个 index 类型形参并返回 char 的成员函数的指针。可以通过传递 Screen 类中适当成员函数的指针或地址调用 action 函数: Screen myScreen; // equivalent calls: action(myScreen); // uses the default argument action(myScreen, get); // uses the variable get that we previously defined action(myScreen, &Screen::get); // pass address explicitly 18.3.2. Using a Pointer to Class Member18.3.2. 使用类成员指针Analogous to the member access operators, operators. and ->, are two new operators, .* and .->, that let us bind a pointer to member to an actual object. The left-hand operand of these operators must be an object of or pointer to the class type, respectively. The right-hand operand is a pointer to a member of that type: 类似于成员访问操作符 . 和 ->,.* 和 -> 是两个新的操作符,它们使我们能够将成员指针绑定到实际对象。这两个操作符的左操作数必须是类类型的对象或类类型的指针,右操作数是该类型的成员指针。
Using a Pointer to Member Function使用成员函数的指针Using a pointer to member, we could call the version of get that takes no parameters as follows: 使用成员指针,可以这样调用不带形参的 get 函数版本: // pmf points to the Screen get member that takes no arguments 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
Without the parentheses, 没有括号,就会将 myScreen.*pmf() would be interpreted to mean 解释为 myScreen.*(pmf()) This code says to call the function named pmf and bind its return value to the pointer to member object operator (.*). Of course, the type of pmf does not support such a use, and a compile-time error would be generated. 这个代码是说,调用名为 pmf 的函数,并将它的返回值绑定到成员对象操作符(.*)的指针。当然,pmf 的类型不支持这样的使用,且会产生编译时错误。 As with any other function call, we can also pass arguments in a call made through a pointer to member function: 像任何其他函数一样,也可以在通过成员函数指针进行的调用中传递实参: char (Screen::*pmf2)(Screen::index, Screen::index) const; pmf2 = &Screen::get; Screen myScreen; char c1 = myScreen.get(0,0); // call two-parameter version of get char c2 = (myScreen.*pmf2)(0,0); // equivalent call to get Using a Pointer to Data Member使用数据成员的指针The same pointer-to-member operators are used to access data members: 相同的成员指针操作符用于访问数据成员: 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 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. 函数指针和成员函数指针的一个公共用途是,将它们存储在函数表中,函数表是函数指针的集合,在运行时从中选择给定调用。 For a class that has several members of the same type, such a table can be used to select one from the set of these members. Let's assume that our Screen class is extended to contain several member functions, each of which moves the cursor in a particular direction: 对具有几个相同类型成员的类而言,可以使用这样的表来从这些成员的集合中选择一个。假定扩展 Screen 类以包含几个成员函数,其中每一个在特定方向移动光标: class Screen { public: // other interface and implementation members as before Screen& home(); // cursor movement functions Screen& forward(); Screen& back(); Screen& up(); Screen& down(); }; Each of these new functions takes no parameters and returns a reference to the Screen on which it was invoked. 这些新函数的每一个都不接受形参,并返回调用它的对象的引用。 Using the Function-Pointer Table使用函数指针表We might want to define a move function that could call any one of these functions and perform the indicated action. To support this new function, we'll add a static member to Screen that will be an array of pointers to the cursor movement functions: 我们可能希望定义一个 move 函数,它可以调用这些函数中的任意一个并执行指定动作。为了支持这个新函数,我们将在 Screen 中增加一个 static 成员,该成员是光标移动函数的指针的数组: 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); }; The array named Menu will hold pointers to each of the cursor movement functions. Those functions will be stored at the offsets corresponding to the enumerators in Directions. The move function takes an enumerator and calls the appropriate function: 名为 Menu 的数组将保存指向每个光标移动函数的指针,将在对应于 Directions 中枚举成员的偏移位置保存那些函数,move 函数接受枚举成员并调用适当函数: 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; } The call inside move is evaluated as follows: The Menu element indexed by cm is fetched. That element is a pointer to a member function of the Screen class. We call the member function to which that element points on behalf of the object to which this points. 这样计算 move 内部的调用:获取由 cm 索引的 Menu 元素(该元素是 Screen 类成员函数的指针),代表 this 指向的对象调用该元素指向的成员函数。 When we call move, we pass it an enumerator that indicates which direction to move the cursor: 调用 move 时,传给它一个枚举成员,指出向哪个方向移动光标: Screen myScreen; myScreen.move(Screen::HOME); // invokes myScreen.home myScreen.move(Screen::DOWN); // invokes myScreen.down Defining a Table of Member Function Pointers定义成员函数指针表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, }; ![]() |
Exercises Section 18.3.2
|