C + + object model--pointer to Member function (Pointer-to-member Functions) (fourth chapter)

Source: Internet
Author: User

4.4 Pointer to Member function (Pointer-to-member Functions) take a nonstatic data member address, the result is the member in the class layout of the byte position (plus 1), it is an incomplete value, need to be bound to the address of a class object, to be able to be accessed.
take the address of a nonstatic member function, and if the function is nonvirtual, the result is a real address in memory. However, this value is also incomplete, and it needs to be bound to the address of a class object. To be able to invoke the function through it, all nonstatic member functions require the address of the object (as indicated by the parameter this).
A pointer to the member function whose declaration syntax is as follows:
double//return type (point::*//Class The function was member PMF)//name of the pointer to member ();//Argument list
You can then define and initialize the pointer like this:
Double (point::* coord) () = &Point::x;
You can also specify values like this:
Coord = &Point::y;
To invoke it, you can do this:
(Origin.*coord) ();
Or
(Ptr->*coord) ();
These actions are translated by the compiler to:
(coord) (&origin);
And
(coord) (PTR);
The declaration syntax of a pointer to the member function, and a pointer to the member selection operator, which acts as the space reservation for the this pointer . It's AlsoThe reason why the static member function (without this pointer) is a "function pointer" and not "pointer to member function".
using a "member function pointer" is no more expensive than using a "nonmember function pointer" If it is not used for virtual function, multiple inheritance, virtual base class, and so on. .The three cases above are too complex for the type and invocation of the member function pointer. In fact, for those classes that do not have virtual functions or virtual base class, or multiple base class, The compiler can provide them with the same efficiency. The next section discusses why virtual function appears, making the "member function pointer" more complicated.

Pointers to "virtual Member Functions" supportedNote the following program fragment:
Float (point::* PMF) () = &Point::z; Point *ptr = new Point3D;
PMF, a pointer to the member function, is set to the address of Point::z () (a virtual function), and PTR is specified with a Point3D object, if Z () is called directly via PTR:
Ptr->z ();
is called Point3d::z (), but what if Z () is called indirectly from PMF?
(PTR->PMF) ();
is the point3d::z () still called? The virtual mechanism can still be shipped with the "pointer to member function"Is that OK? The answer is yes, and how does the question be achieved?
For a nonstatic member function to take its address, it will get the address of the functions in memory, but in the face of a virtual function, its address is unknown at compile time, can only be the virtual function in its related The index value in virtual table. That is, for a virtual member function to take its address, all you can get is an index value.
For example, suppose you have the following point declaration:
Class Point {public:virtual ~point (); float x (); float y (); virtual float z ();};
However get the address of destructor:
&Point::~Point;
The result is 1, taking the address of X () or Y ():
&point::x (); &point::y ();
The result is the address of the function in memory, because they are not virtual, take the address of Z ():
&point::z ();
The result is 2, which is called by PMF to call Z (), which is converted internally into a compile-time formula, in the following general form:
(*ptr->vptr[(int) PMF]) (PTR);
Evaluating the evaluation of a pointer to member function (evaluted) is complicated by the fact that the value has two meanings, and its invocation is different from the normal call operation. The internal definition of PMF, which is:
Float (point::* PMF) ();
The function must be allowed to address the nonvirtual X () and Virtual Z () two member functions, which have the same prototype:
Both can be assigned to Pmffloat Point::x () {return _x;} Float Point::z () {return 0;}
Just One represents the memory address and the other represents the index value in virtual table. Therefore, the compiler must define PMF so that it can (1) have two more values, (2) More importantly, its value can be distinguished by whether it represents the memory address or the index value in virtual table.

Under multiple inheritance, a pointer to member functions to allow pointers to member functions to support multiple inheritance and virtual inheritance, Stroustrup designs the following structure:
General structure to support pointers to member functions under multiple inheritance struct __mptr {int delta;int index;union {ptrtofunc faddr;int v_offset;};};
What do they have to show? Index and FADDR have the virtual table index and the nonvirtual member function address, respectively (not at the same time).In this model, a call operation like this:
(PTR->*PMF) ();
will become:
(Pmf.index < 0)?//Non-virtual Invocation (*PMF.FADDR) (PTR)://Virtual Invocation (*ptr->vptr[pmf.index] (PTR));
The criticism of this approach is that each invocation operation has to pay the above cost to check whether it is virtual or nonvirtual. Microsoft took the check off and imported a so-called Vcall thunk. Under this strategy, the FADDR is either the true member function address (if the function is nonvirtual) or Vcall The address of the thunk. So the virtual or novirtual function call operation is transparent, and Vcall Thunk selects and invokes the appropriate slot in the related virtual table.
Another side effect of this struct is that when a pointer to a constant value is passed to the member function, it needs to produce a temporary object. For example, if you do this:
extern Point3D foo (const point3ed&, Point3D (Point3D::*) ()), void Bar (const point3d& p) {Point3D pt = foo (p, &po Int3d::normal);}
Where the value of &point3d::normal is similar to this:
{0,-1, 10727417}
will need to produce a temporary object with a definite initial value:
__mptr temp = {0,-1, 10727417}foo (P, temp);
The structure at the beginning of this section, the Delta field represents the offset value of the this pointer. The V_offset field places the vptr position of the base class with the second or successor of virtual (or multiple inheritance). If vptr is placed in the class by the compiler At the beginning of the object, this field is not necessary at the expense of C object compatibility. These fields are only necessary in the case of multiple inheritance or virtual inheritance, and many compilers provide multiple pointers to member functions within themselves based on different class attributes. Microsoft, for example, offers three flavors:
1. A single instance of inheritance (with Vcall thunk address or function address)
2. A multiple-inheritance instance (with Faddr and Delta two members)
3. A virtual inheritance instance (with four members)

"Pointer to member functions" efficiencyIn the following set of tests, the cross_product () function is called in the following way:
1. A pointer to the nonmember function
2. A pointer to the class member function
3. A pointer to virtual member function
4. Nonvirtual and virtual member function call under multiple inheritance
5. Nonvirtual and virtual member function call under dummy inheritance.

The first test (a pointer to the nonmember function) is performed in the following manner:
point3d* (*PF) (const point3d&, const Point3D &) = cross_product;for (int iters = 0; iters < 10000000; iters++) (*PF) (PA, PB); return 0;
A second Test the Declaration and invocation operations (pointers to member function) are as follows:
point3d* (Point3D::* PMF) (const Point3D &) const = &point3d::cross_product;for (int iters = 0; iters < 10000000; iters++) (PA.*PMF) (PB);
The above operation is converted to the following internal form, and the following function is called:
(PA.*PMF) (PB);
will be translated into such a judgment:
Pmf.index < 0? (*PMF.FADDR) (&pa + Pmf.delta, pb): (*PA.__VPTR__POINT3D[PMF.INDEX].FADDR) (&pa + Pa.__vptr__point3d[pmf.index].delta, pb);
A pointer to member function is a structure that contains three fields: Index,faddr and Delta.index are not the index values of a related virtual table, or 1 means that the function is Nonvirtual.faddr the address with nonvirtual member function. The delta has a possible this pointer adjustment.

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

C + + object model--pointer to Member function (Pointer-to-member Functions) (fourth chapter)

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.