C ++ learning starts from scratch (4)

Source: Internet
Author: User

Virtual Functions

Virtual inherits the ing element of a function type. According to virtual inheritance, the address of the function is obtained indirectly, but the result is the value of this parameter indirectly. To indirectly obtain the function address, C ++ also proposes a syntax-virtual function. When writing a function declaration or definition in the Type Definition character "{}", add the keyword "virtual" before the declaration or Definition Statement, as shown below:

Struct A {long a; virtual void ABC (), BCD ();};

Void A: ABC () {a = 10;} void A: BCD () {a = 5 ;}

The above is equivalent to the following:

Struct A {void (A: * pF) (); long a; void ABC (), BCD (); ();};

Void A: ABC () {a = 10;} void A: BCD () {a = 5 ;}

Void (A: * AVF []) () = {A: ABC, A: BCD}; void A: A () {pF = AVF ;}

Here, A member A: pF, like the previous Virtual Table, is A pointer pointing to an array called Virtual Function Table ), is an array of function pointers. When A: ABC is used in this way, the sequence number of A: ABC in A: pF is obtained indirectly by A: pF. Therefore, A a;. ABC (); will be equivalent to (. * (. pF [0]) ();. Therefore, the length of structure A is 8 bytes. Let's look at the following code:

Struct B: public A {long B; void ABC () ;}; struct C: public A {long c; virtual void

ABC ();};

Struct BB: public B {long bb; void ABC () ;}; struct CC: public C {long cc; void

ABC ();};

Void main () {BB bb; bb. ABC (); CC cc; cc. cc = 10 ;}

First, the above execution of bb. ABC () does not provide the definition of BB: ABC or B: ABC. Therefore, although the above compilation is successful, the connection will fail. Second, no cc. ABC () is executed above, but CC: ABC is not defined during connection to indicate that CC: ABC is needed here. Why? Because CC instances are generated, and CC: pF needs to be correctly initialized in the default constructor automatically generated by the compiler for CC. It needs the address of CC: ABC to fill in. Then, the following function definitions are given.

Void B: ABC () {B = 13;} void C: ABC () {c = 13 ;}

Void BB: ABC () {bb = 13; B = 10;} void CC: ABC () {cc = 13; c = 10 ;}

After the above, for bb. ABC ();, equivalent to bb. BB: ABC (); although there are three BB: ABC ing elements, only one ing element of the type is void (BB ::)(), its ing BB: ABC address. Because BB: ABC does not use virtual modification, the above is equivalent to bb. BB: ABC (); Not (bb. * (pF [0]) ();, bb will be 13. The same is true for cc. ABC (); cc will be 13.

For (B *) & bb)-> ABC ();, because the left-side type is B *, It is (B *) & bb)-> B :: ABC (); because B: ABC is not defined as a virtual function, it is equivalent to (B *) & bb)-> B: ABC ();, B will be 13. For (C *) & cc)-> ABC ();, it will also be (C *) & cc)-> C: ABC ();, but C:: ABC is modified as a virtual function, which is equivalent to C * pC = & cc; (pC-> * (pC-> pF [0]) ();. Here, the cc is first converted to a C instance with an offset of 0. Then, indirectly obtain the function address based on pC-> pF [0]. For CC: ABC, c is 10. Because cc is a CC instance, it will be filled with cc. pF when it is constructed.

As follows:

Void (CC: * CCVF []) () = {CC: ABC, CC: BCD}; CC: CC () {cc. pF = & CCVF ;}

Therefore, pC-> ABC (); the result of calling is CC: ABC instead of C: ABC, which is caused by indirectly obtaining the function address due to virtual. Similarly, for (A *) & cc)-> ABC (); and (A *) & bb)-> ABC ();, CC :: ABC and BB: ABC. However, note that (pC-> * (pC-> pF [0]) (); In, the pC type is C, the CC: ABC returned by pC-> pF [0] is of the void (CC:) () type. How can I perform implicit type conversion for the instance in the above example? If you do not perform this operation, the operation will be incorrect. As mentioned above, the length of each member of CCVF is 8 bytes, And the offset of the other 4 bytes is recorded. However, most classes do not need to be offset (as shown in the preceding example, if the CC instance is converted to instance A, the offset is 0). This method wastes some resources. The method provided by VC is as follows. Assume that the address of CC: ABC is 6000, and the address of P is 6000, whereas CC :: a_thunk corresponds to 5990.

Void CC: A_thunk (void * this)

{

This = (char *) this) + diff;

P:

// CC: normal code of ABC

}

Therefore, the value of pC-> pF [0] Is 5990, instead of the 6000 value corresponding to CC: ABC. The diff above is the corresponding offset.

Shift. For the above example, diff should be 0, so the actual pC-> pF [0] value is still 6000 (because the offset is 0, no

It must be 5990 ). This method is called thunk, indicating the short code to complete simple functions. For multi-inheritance:

Struct D: public A {long d ;};

Struct E: public B, public C, public D {long e; void ABC () {e = 10 ;}};

There will be three virtual function tables above, because B, C, and D each carry a virtual function table (because they are generated from ).

The result is equivalent:

Struct E

{

Void (E: * B _pF) (); long B _a, B;

Void (E: * C_pF) (); long C_a, c;

Void (E: * D_pF) (); long D_a, d; long e; void ABC () {e = 10;} E ();

Void E_C_thunk_ABC () {this = (E *) (char *) this)-12); ABC ();}

Void E_D_thunk_ABC () {this = (E *) (char *) this)-24); ABC ();}

};

Void (E: * E_BVF []) () = {E: ABC, E: BCD };

Void (E: * E_CVF []) () = {E: E_C_thunk_ABC, E: BCD };

Void (E: * E_DVF []) () = {E: E_D_thunk_ABC, E: BCD };

E: E () {B _pF = E_BVF; C_pF = E_CVF; D_pF = E_DVF ;}

Result E; C * pC = & e; pC-> ABC (); D * pD = & e; pD-> ABC (); assume that the address of e is 3000, the pC value is 3012, And the pD value is 3024. Result The value of pC-> pF is E_CVF, and the value of pD-> pF is E_DVF, which solves the offset problem. Similarly, for the previous virtual inheritance, when there are multiple virtual class tables in the class, such:

Struct {};

Struct B: virtual public A {}; struct C: virtual public A {}; struct D: virtual public {};

Struct E: public B, public C, public D {};

This is where E will have three virtual tables, and each virtual table will be correctly initialized in the default constructor of E to ensure that the meaning of virtual inheritance is obtained indirectly. The initialization of the above virtual function table is so complicated only to ensure the correctness of the indirect result.

It should be noted that the above _ BVF type is defined as void (E: * []) () only because of the demonstration, and the code should be written as much as possible in line with the syntax, it does not mean that the type of the virtual function can only be void (E ::)(). In reality, the virtual function table is just an array, and each element is 4 bytes in size to record an address. Therefore, you can also:

Struct A {virtual void ABC (); virtual float ABC (double );};

Struct B: public A {void ABC (); float ABC (double );};

B B; A * pA = & B; pA-> ABC (); B: ABC of the call type void (B, while pA-> ABC (34); the call type is B: ABC of float (B:) (double. They are heavy-duty functions. Even if they have the same name, they are two different virtual functions. You should also pay attention to the virtual and previous public information, which are only provided to the compiler in terms of syntax. the information they provide is applicable to some special situations, it is not applicable to all places where numbers are used, so it cannot be a number. Therefore, virtual is not a type modifier. It modifies a member function and only tells the compiler to indirectly obtain the address where the member function is used.

Why do we need to provide the concept of virtual reality? That is, what is the significance of virtual functions and virtual inheritance? Due to space limitations, we will discuss their significance in the next part of this article, and explain the issues such as polymorphism and instance replication in real time.

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.