instance resolves member function pointers for classes in C + + _c language

Source: Internet
Author: User

The C language pointer is quite flexible, but it is also quite easy to make mistakes. Many C-language beginners, even the C-language veteran, are apt to stumble under the C-language pointer. But there is no denying that the position of the pointer in the C language is extremely important, perhaps to a radical point: the C program without pointers is not a real C program.
But the C + + pointer often gives me a feeling of being shackled. C + + has more stringent static types than C, more emphasis on type safety, and emphasis on compile-time checks. Therefore, for the C language is the most easily wrong pointers, but also can not let go: C + + pointer is divided into data pointers, data member pointers, function pointers, member function pointers, and can not easily convert to each other. and the declaration formats of these pointers are different:

Data pointers T
Member Data pointers T::*
function pointers R (*) (...)
member function pointers R (T::*) (...)

A more important difference is that the space the pointer occupies is different. Even in a 32-bit system, the space may be 4 bytes, 8 bytes, 12 bytes, or even 16 bytes, which varies greatly depending on the platform and compiler.
Although C + + still has a universal pointer void*, but it belongs to the object of being denounced, and can no longer "omnipotent." It cannot be converted into a member pointer.
As a result, the C + + pointer becomes awkward: we need a pointer that can point to the same type of data, whether it's regular or member data; we need a pointer that can point to a function of the same type, whether it's a static function or a member function. But none, at least from the current C + + standard, has not been seen.
In programming work, you often encounter the requirement of calling member functions in a "class" by function pointers, for example, when the sort function qsort in a C + + standard library is used in a class, the Qsort parameter requires a "comparison function" pointer, if the "class" uses a member function as a "comparison function", You need to pass the pointer of this member function to qsort for its invocation. The member functions discussed in this article that invoke the "class" with pointers include the following three cases:

(1). Assign the member function pointer of class to the same type of non-member function pointer, such as:

Example 1

#include <stdlib.h> 
typedef void (*function1) ();//define a function pointer type. 
Function1 F1; 
Class Test1 
{public 
:  
//... The called member function. 
void Memberfun1 () {printf ("%s \ n", "calling test3::memberfun2 OK");};//  
void Memberfun2 () 
{ 
f1= Reinterpret_cast<function1> (MEMBERFUN1);//Assign member function pointers to F1. Compilation error. 
F1 (); 
} 
... 
}; 
int main () 
{ 
Test1 t1; 
t1. Memberfun2 (); 
return 0; 
} 

(2) in a "class", there are standard library functions, such as qsort, or other global functions, which invoke the member functions of the class with function pointers. Such as:

Example 2:

#include <stdlib.h> 
class Test2 
{ 
private:  
int data[2]; 
... Public: 
//... 
int __cdecl Compare (const void* elem1, const void* ELEM2)//member functions. 
{  
printf ("%s \ n", "calling Test2::memberfun OK"); 
return * ((int*) elem1)-* ((int*) elem2);  
} 
void Memberfun ()  
{  
data[0]=2; data[1]=5; 
Qsort (data, 2, sizeof (int), Compare); The standard library function calls into 
//member functions. Compilation error. 
} 
... 
}; 
int main () 
{ 
Test2 t2; 
T2. Memberfun (); Call a member function. return 
0; 
} 

(3) Within the same "class", a member function calls another member function, such as:

Example 3:

#include "stdlib.h" 
class Test3 
{public 
: 
//... 
void Memberfun1 (void (* F2) ()) {F2 ();}//member function 1 calls member function//2. 
void Memberfun2 () {printf ("%s \ n", "calling test3::memberfun2 OK");}//member function 2. 
void Memberfun3 () {Memberfun1 (Memberfun2);}//Compile error//... 
}; 
int main () 
{ 
Test3 t3; 
T3. Memberfun3 (); Call a member function. return 
0; 
} 

There are no significant errors in the code syntax for the above three cases, in some older compilation environments, such as VC + + 4.0, which can usually be compiled or at most a problem alert (Warning). Later compilation tools, such as vc++6.0 and other commonly used C + + compiler software, cannot be compiled with the above code and point out the following errors (in the third case, compiled with VC + + 6.0 for example):

Error C2664: ' Memberfun1 ': cannot convert parameter 1 from ' void (void) ' to ' void (__cdecl *) (void) '
None of the Func tions with the-name in scope match the target type

That is, the function type called in the MEMBERFUN1 parameter is incorrect.

As indicated above, it is not possible to eliminate errors by simply changing the type of the function, but if you take these functions out of the definition of a class without making any changes, you can eliminate errors by compiling, and still, in the third case, the following code can be compiled:

#include <stdlib.h> 
void Memberfun1 (void (* F2) ()) {F2 (),}//The original member function 1 invokes the member function//2. 
void Memberfun2 () {printf ("%s \ n", "calling test3::memberfun2 OK");}//original member function 2. 
void Memberfun3 () {Memberfun1 (Memberfun2);} 
int main () 
{ 
Memberfun3 (); 
return 0; 
} 

The 1th, 2 and 3rd cases are exactly the same.

From this, we can conclude that the reasons for the above three kinds of cases are not based on the function type invocation, but on the "class". Without compiling, a function pointer is used to invoke the member function of the class, and the function is compiled with a function pointer called the non member function, and the functions are of the same type. So, what's the difference between a member function pointer of a class and a non-member function pointer?

In the following program, the sizeof () function allows you to view the length (size) of the member function pointers and the non member function pointers for various "classes" and output to the screen.

#include "stdafx.h" #include <iostream> #include <typeinfo.h> class Test; 
A class that is not defined. 
Class Test2//an empty class. 
{ 
}; 
Class TEST3//a defined classes. 
{public://... void (* memberfun) (); 
void Memberfun1 (void (* F2) ()) {F2 ();}//member function 1 calls member function//2. 
void Memberfun2 ();//member function 2. 
... }; 
Class Test4:virtual Test3, Test2//A classes with virtual inheritance (derivative Class).  
{public:void Memberfun1 (void (* F2) ()) {F2 ();} 
}; 
Class Test5:test3,test2//an inheritance Class (derivative Class).  
{public:void Memberfun1 (void (* F2) ()) {F2 ();} 
 
}; 
 int main () {std::cout << "general function pointer length =" << sizeof (void (*) ()) << ' \ n '; 
 Std::cout << "-member function pointer length of class-" << ' \ n ' << ' \ n '; 
 Std::cout << "TEST3 class member function pointer length =" << sizeof (void (Test3::*) ()) << ' \ n ' << ' \ n '; 
 Std::cout << "TEST5 class member function pointer length =" <<sizeof (void (TEST5:: *) ()) << ' \ n '; 
 Std::cout << "Test4 class member function pointer length =" <<sizeof (void (Test4:: *) ()) << ' \ n '; Std::cout << "Test class member function pointer lengthdegree = "<<sizeof (void (Test::*) ()) << ' \ n '; 
return 0; 
 }

The output is (vc++6.0 compiled, running on the Win98 operating system, and other operating systems may be different):

    • General non-member function pointer length = 4
    • -member function pointer length of class-
    • Test3 class member function pointer length =4
    • TEST5 class member function pointer length =8
    • Test4 class member function pointer length =12
    • Test class member function pointer length =16

The above results show that in the 32-bit WIN98 operating system, the length of the general function pointer is 4 bytes (32 bits), and the length of the member function pointer of the class varies with the definition of the class, the type of inheritance and the relationship of the class, 12-byte (96-bit) of 4-byte (32-bit) of a virtual Inheritance relationship class (Virtual inheritance) (TEST4) with no Inheritance relationship class (TEST3), only a description (declaration) Class not defined (Test) because some information about it is ambiguous. The member function pointer is up to 16 bytes (128 bits) long. Obviously, unlike a general function pointer, a pointer to a member function of class does not only contain information about the address of the member function. And it contains information about the properties of the class, so the general function pointer and the member function pointer of the class are two fundamentally different types, and, of course, you can't call a class's member function directly with a generic function pointer. This is why the three scenarios that are mentioned in this article have been compiled in error. Although compiling with an earlier version of the compilation software is still possible, this can leave the program with serious pitfalls.

As for why the same pointer to the member function of the class, its length is different, from 32 bits to 128 bits, the difference is very large, because did not see the official Microsoft Data can only speculate vc++6.0 at compile time to the class member function pointer optimized to minimize the length of the pointer, After all, using a 128-bit or 96-bit pointer on a 32-bit operating system can have an impact on program performance. However, in any case optimization, the member function pointer of a class containing a certain amount of object (Objects) information is determined. Whether other operating systems and compiler software have done similar processing, readers can use the above program to verify their own.

So, when needed, how do you invoke a member function of a class with a pointer? You can consider the following methods:

(1) Set the member function that needs to be invoked as a static type, such as: In the preceding example 2, the class TEST2 member function compare is defined before the following static is added:

Class Test2 {//... 
int static __cdecl Compare (const void* elem1, const void* ELEM2)//member functions. 
//Other invariant 
} 

The changed code compiles smoothly through. The reason is that the member function of the static type is separate from the class, and its function pointer does not contain object information, which is consistent with the general function pointer. This approach, although simple, has two disadvantages: 1, members of any class cannot appear within the defined function member definition (including variables and functions), 2, and because static members are used, the class is restricted when it is inherited.

(2) using a function parameter containing the object information of the static type of member functions for relay indirectly call other member functions, for example 3, the class Test3 as follows, the main () function is unchanged, you can successfully compile:

Class Test3 
{public 
: 
//... 
void static __cdecl Helper (test3* test3) 
{ 
test3->memberfun2 (); 
} 
void Memberfun1 (* F2) (test3*) {F2 (this);}//Pass object information to the helper function. 
void Memberfun2 () {printf ("%s \ n", "calling test3::memberfun2 OK");}//member function 2. 
void Memberfun3 () {Memberfun1 (Helper);}  
... 
}; 

This indirect approach has no limitations on member functions, overcoming the disadvantage of the first method that member functions cannot use members of any class, but because of static members, inheritance of the class is still constrained.

(3) using a full function (global function) to invoke the member function of the class indirectly, still take example 3 as the following modification (vc++6.0 compiled):

Class Test3; 
void __cdecl Helper (test3* test3); 
Class Test3 
{public 
: 
//... 
void Memberfun1 (void (* F2) (test3*)) {F2 (this);}//member function 1 invoke member function//2. 
void Memberfun2 () {printf ("%s \ n", "calling test3::memberfun2 OK");}//member function 2. 
void Memberfun3 () {Memberfun1 (Helper);}  
... 
}; 
 
void __cdecl Helper (test3* test3) 
{ 
test3->memberfun2 (); 
}; 

This method has no requirements for member functions, but requires more code.

In addition to the above three methods there are other methods, such as the assembly level can modify the code to solve the above problems, such as the scope of this article.

Conclusion: The function pointer can not directly invoke the member function of the class, so it is necessary to take indirect method, because the member function pointer is different from the general function pointer, and the member function pointer contains the information of the object, besides the address information. This article provides three ways to indirectly invoke member functions. These three methods have their own advantages and disadvantages and apply to different occasions.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.