Revision on Pointers

Total Page:16

File Type:pdf, Size:1020Kb

Revision on Pointers

Pointer To Class Members

Question

What is the difference between ‘pointer to function ‘ and ‘pointer to member function’?

NOTE : Please review notes on function pointers before proceeding.

Introduction

Before we start our discussion, please note that pointer to member functions are very different compared with other kinds of pointers including ordinary pointer to function. The pointer to member function is an available in C++ but not C.

Consider the example below:

1. #include 2. #include 3. 4. class Test 5. { 6. public: 7. static int func2(int i,int j) { return i-j;} 8. int func3(int i,int j) { return i+j;} 9. int func4(int i,int j) { return i-j;} 10. }; 11. 12. int func1(int i,int j) //NOT a member of class Test 13. { return i+j;} 14. 15. void main() 16. { 17. cout << typeid(func1).name(); //output: int (*)(int,int) 18. cout << typeid(Test::func2).name(); //output: int (*)(int,int) 19. cout << typeid(Test::func3).name(); //output: int (Test::*)(int,int) 20. }

In the above example, func1 (an ordinary function) has type: int (*)(int,int) func2 (a static member function) has type: int (*)(int,int) func3 (a non-static member function) has type: int (Test::*)(int,int)

Therefore, it is evident that if we would to create different pointers to point to these function, the pointers to ordinary function and pointers to class member functions would be very much different. Declaring Pointer to Member Function

To declare the different pointers to point to each of these functions, we must create the compatible pointers as shown below: int ( *p1)(int,int); p1 = func1; int ( *p2)(int,int); p2 = Test::func2; int (Test::*p3)(int,int); p3 = Test::func3; or initialize the pointers as they are declared” int ( *p1)(int,int) = func1; int ( *p2)(int,int) = Test::func2; int (Test::*p3)(int,int) = Test::func3;

From here we can also see that pointer to static member function is very much similar to pointer to ordinary function. We would restrict our discussion on pointer to non-static member function from now on.

Note also that to declare a pointer to member function, we simply include the class name plus the scope resolution operator (i.e. ‘Test::’ in this example) before the asterix (‘*’) symbol.

IMPORTANT NOTE : most book put an amersand (‘&’) before the class function as below: int (Test::*p3)(int,int) = &Test::func2; This is equally valid.

Also note that the pointer can only point to member function with the correct access privilege. For example, a pointer to member function that belongs to main() can only point to public member function of Test but NOT private member function.

Using Pointer to Member Function

Pointer to Ordinary Function / Pointer to Static Member Function

To invoke the function pointed by pointer to ordinary function, we would write as below (using p1 declared above): int n = (*p1)(4,7); or: int n = p1(4,7); This would be equivalent to writing: int n = func1(4,7);

We can do the same for pointer to static member function since static member function has the same type as ordinary function. This is shown below: int n = p2(4,7); This would be equivalent to writing: int n = Test::func2(4,7);

Pointer to Non-Static Member Function However, for pointer to member function p3, we can NOT invoke the member function this way: int n = (*p2)(4,7); //SYNTAX ERROR int n = p2(4,7); //SYNTAX ERROR

Why?

The reason is very simple, any non-static member function can ONLY be invoked by associating it with an instance object of the class. That is to say: you can invoke func2 as below: int n = Test::func2(4,7); because func2 is a static member function but you can NOT invoke func3 as below: int n = Test::func3(4,7); instead we need to first define an instant of the class and associate the function name with the instant of the class. This is shown below: Test t,s; int m = t.func3(4,7); int n = s.func3(4,8);

Similarly, to invoke the member function through the pointer to member function p3 declared earlier, we can write this way: int (Test::*p3)(int,int) = Test::func3; //as declared earlier Test t,s; int m = (t.*p3)(2,3); int n = (s.*p3)(4,5); this would be equivalent of writing: int m = func3(2,3); int n = func3(4,5); later we can always reassign the pointer to point to a different member function, this is shown below: p3 = Test::func4; int m = (t.*p3)(2,3); int n = (s.*p3)(4,5); this would be equivalent of writing: int m = func4(2,3); int n = func4(4,5);

From these we can observe that: 1. A pointer to member function can ONLY be used to invoke the member function by associating itself with an instant of the class. 2. The association of the pointer and the instant of the object can be done either during compile- time as well as run-time. 3. The association of the pointer and the class member function can also be done during run-time. Based on these facts, we have the following definition:

. If an object is associated by the compiler to a function at compile time, this is called early binding or static binding. If, by contrast, the compiler can not associate the object to a function at compile time, and the function to be associated with the object is chosen at run time, this is called late binding or dynamic binding

C++ offers both early binding and also late binding. The ability to do late binding is very important in C++ especially in implementing inheritance. The reason is becasue sometimes the exact identity of an object is not known until run time and thus the actual functions to be called can only be chosen during run time.

Comparing the Syntax

The difference between pointer to ordinary function and pointer to member function is highlighted below:

Pointer to ordinary function: int ( *p1)(int,int); p1 = func1; int n = (*p1)(4,7);

Pointer to ordinary function: int (Test::*p3)(int,int); p3 = Test::func3; Test t; int m = (t.*p3)(2,3); Test* s = &t; int m = (t->*p3)(2,3);

In C++, the symbol dot-asterix (‘.*’) is considered to be ONE single operator. This is also true for symbol arrow-asterix (‘->*).

Note that the following line would produced syntax error: int m = (*t.p3)(2,3); //SYNTAX ERROR this is because t.p3 implies that p3 is a member of t and this is NOT true. Only *p3 (the function pointed by p3) is a member of t.

A Complete Example of Pointer to Member Functions

1. //This program demonstrate pointer to class member functions 2. 3. #include 4. #include 5. 6. #define CAT 0 7. #define DOG 1 8. #define COW 2 9. 10. class Animal 11. { 12. public: 13. int id; 14. void catsound() { cout << "Meow! " << endl; } 15. void dogsound() { cout << "Wuh Wuh! " << endl; } 16. void cowsound() { cout << "Mooooow! " << endl; } 17. }; 18. 19. void main() 20. { 21. void (Animal::*sound[3])() = 22. { Animal::catsound,Animal::dogsound,Animal::cowsound }; 23. 24. Animal animal[5]; 25. int choice; 26. for (int i=0;i<5;i++) 27. { 28. cout << "Enter type of animal (0=Cat 1=Dog 2=Cow) : "; 29. cin >> choice; 30. animal[i].id = choice; 31. } 32. 33. for (int i=0;i<5;i++) 34. ( animal[i].*sound[animal[i].id] )(); 35. 36. getch(); 37. }

Pointer to Data Members

Pointer to class data members has the same concept as pointer to member functions. Pointer to member data has a much simpler form.

Example:

38. #include 39. #include 40. #include 41. 42. class Test 43. { 44. public: 45. int data1,data2; 46. }; 47. 48. void main() 49. { 50. int Test::*q = &Test::data1; //must have the ampersand (&) 51. 52. cout << typeid(q).name() << endl; //output: int Test::* 53. 54. Test t,s; 55. t.data1 = 3; 56. t.data2 = 4; 57. s.data1 = 5; 58. s.data2 = 6; 59. 60. cout << t.*q << endl; //output: 3 //NOTE: .* is a single operator 61. cout << s.*q << endl; //output: 5 62. 63. q = &Test::data2; //re-assign //must have the ampersand (&) 64. 65. cout << t.*q << endl; //output: 4 66. cout << s.*q << endl; //output: 6 67. 68. t.*q = 7; //OK, this is valid 69. s.*q = 8; //OK, this is valid 70. cout << t.data2 << endl; //output: 7 71. cout << s.data2 << endl; //output: 8 72. 73. q = &t.data2; //Syntax Error! Can not convert 'int *' to 'int Test::*' 74. *q = 9; //Syntax Error! because q is NOT a absolute pointer, 75. *(t.q) = 10; //Syntax Error! because q is not a member of Test 76. 77. //What if we have a pointer to Test? 78. q = Test::data1; 79. Test r; 80. r.data1 = 11; 81. Test *pt = &r; 82. 83. cout << r.*q << endl; //output: 11 84. cout << pt->*q << endl; //output: 11 //NOTE: ->* is a single operator 85. 86. getch(); 87. }

Recommended publications