Code Structure Analysis
Code Structure Analysis
Home| Services| C++ Grammar | Examples of Analysis | Contacts|

Pointers to class member functions and data fields of the C++ classes

Pointers to the member functions are rarely used, and in general, it might be better to avoid using them because there is a good chance that the reader of the program will fail to understand what this notation means. Nevertheless, sometimes they are helpful. From time to time they are used in the code, and it is necessary to understand or modify such code.

The idea of the pointers to members is similar to simple pointers. Simple pointer can point either to a piece of data or to a function. Member pointer can point either to a data field of a structure (union/class) or to a member function. These pointers are always typed. Data member pointer can point to any non-static member of the structure that has specific type. Function member pointer can point to any non-static member function that has certain signature. It makes sense to use member pointers only when structure or class has more than one data member of the same type or when several member functions share the same signature. C++ does not have a concept of a member references.

Main difference between simple pointers and member pointers is that using the member pointer requires an instance of the object. An instance of the object tells what object should be processed and the value of the pointer tells what data field of the object should be used or what member function should be called. Value of the member pointer is conceptually equivalent to the offset from the beginning of the object to its member.

Look at the small sample program:

1
2 class SomeClass
3 {
4 public:
5
6     void    F1(int x);
7     void    F2(int x);
8
9     short    d1, d2;
10 };
11
12 void main()
13 {
14     // Declaring and assigning pointer to member function.
15     void (SomeClass::*ptr1)(int x1);
16     ptr1 = SomeClass::F1;
17
18     // Declaring and assigning pointer to non static data field.
19     short SomeClass::*ptr2;
20     ptr2 = &SomeClass::d1;
21
22     // Using the member pointers.
23     SomeClass ab;
24     (ab.*ptr1)(2);
25     short var1 = ab.*ptr2;
26
27     // Pointer to member function as a data type.
28     typedef void (SomeClass::*MethodPtr)(int x1);
29     MethodPtr ptr3 = SomeClass::F2;
30
31     // Pointer to data field as a data type.
32     typedef short SomeClass::*DataFieldPtr;
33     DataFieldPtr ptr4 = &SomeClass::d2;
34
35     // Using the member pointers.
36     class SomeClass *pab = &ab;
37     (pab->*ptr3)(4);
38     short var2 = pab->*ptr4;
39 }
40

This program has a class that has two member functions and two data fields. The function main below uses member pointers to access elements of this class.

Here are pieces of the C++ grammar that are related to assembling the declarator:

R109 Declarator:  DirectDeclarator ;
R110 Declarator:  PtrOperator Declarator ;
R111 DirectDeclarator:  ExpressionId ;
R114 DirectDeclarator:  DirectDeclarator ParameterDeclarationClause ;
R138 PtrOperator:  SimpleOrQualifiedId '::' '*' ;

Rules R109 and R110 tell that declarator can contain any number of PtrOperator symbols. Note that these rules also tell that PtrOperator symbols should be considered only after assembling the DirectDeclarator. Rules R111 and R114 show how ParameterDeclarationClause is added. This symbol describes parameters of the function. Finally the rule R138 describes one of the possible forms of the PtrOperator. Other forms of the PtrOperator are not shows here.

Note that when the pointers to member functions are defined parentheses are used in a similar way when simple pointers to functions are defined. Actually these parentheses tell that this is a pointer to function. Without parentheses these declarations will describe a function that returns a pointer. Defining data member pointers does not require parentheses.

These pieces of the C++ grammar are used for parsing expressions that contain pointers to the class members:

R421 PmExpression:  CastExpression ;
R422 PmExpression:  PmExpression '.*' CastExpression ;
R423 PmExpression:  PmExpression '->*' CastExpression ;
R470 PostfixExpression:  PrimaryExpression ;
R478 PostfixExpression:  PostfixExpression '(' ')' ;
R479 PostfixExpression:  PostfixExpression '(' ExpressionsList ')' ;

Rules R421, R422 and R423 show that operators for using the member pointers are simple binary operators from the grammar stand point. Rules R470, R478 and R479 describe scanning the function call. Note that rules for function call operate with a lower level non-terminal than the rules that describe using the member pointers. This means that function call operation has higher priority. This is why lines 21 and 31 have parentheses. Similar thing happens when simple pointers to functions are used.

Once again, the member pointer is always typed. Using a simple pointer is an unary operation, while using a member pointer is a binary operation. The first operand is an instance of the object and the value of the member pointer describes to the member of the class that should be used.

Notes on the base classes and derived classes. C++ can silently cast derived class to its base class. This rule also appllies to the member pointers:

  • Method or data member of a base class can be assigned to the member pointer of a derived class.
  • Instance of a derived class can be used with a member pointer of a base class.
If the rules above are violated, this is a syntax error.


If you find this article useful or if you want to propose topic for a similar article, send us a note using the contacts page.