Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Virtual functions in C++

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article is mainly about "virtual functions in C++". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Next, let the editor take you to learn the virtual functions in C++.

The assembly language is difficult to read, especially for some friends who do not have the basis of assembly. therefore, this paper translates the assembly into the corresponding C language to facilitate readers to analyze the problem.

1. Code

In order to express the problem conveniently, this paper selects two classes with only virtual functions and, of course, its constructors, as follows:

[cpp] view

Plaincopyprint?

Class Base

{

Public:

Virtual void f () {}

Virtual void g () {}

}

Class Derive: public Base

{

Public:

Virtual void f () {}

}

Int main ()

{

Derive d

Base * pb

Pb = & d

Pb- > f ()

Return 0

}

two。 Virtual function table of two classes (vtable)

The above C++ code can be generated into its corresponding assembly code using the test.cpp +-Wall-S command.

[cpp] view

Plaincopyprint?

_ ZTV4Base:

.long 0

.long _ ZTI4Base

.long _ ZN4Base1fEv

.long _ ZN4Base1gEv

.weak _ ZTS6Derive

.section .rodata. _ ZTS6Derive, "aG", @ progbits,_ZTS6Derive,comdat

.type _ ZTS6Derive, @ object

.size _ ZTS6Derive, 8

_ ZTV4Base is a data symbol, and its naming convention is based on the internal rules of Gmail +. If you want to see the symbol name that really represents C++, you can use the c++filt command to convert it, for example:

[lyt@t468 ~] $c++filt _ ZTV4Base

Vtable for Base

The _ ZTV4Base symbol (or variable) can be seen as an array, whose first item is 0, and the second item _ ZIT4Base is type information about Base, which is related to typeid. For the sake of discussion, we omit these two items of data. Therefore, the structure of the vtable of the Base class is translated into the corresponding C language definition as follows:

[cpp] view

Plaincopyprint?

Unsigned long Base_vtable [] = {

& Base::f ()

& Base::g ()

}

Derive is even more similar, only slightly different:

[cpp] view

Plaincopyprint?

_ ZTV6Derive:

.long 0

.long _ ZTI6Derive

.long _ ZN6Derive1fEv

.long _ ZN4Base1gEv

.weak _ ZTV4Base

.section .rodata. _ ZTV4Base, "aG", @ progbits,_ZTV4Base,comdat

.align 8

.type _ ZTV4Base, @ object

.size _ ZTV4Base, 16

The corresponding C language is defined as follows:

[cpp] view

Plaincopyprint?

Unsigned long Derive_vtable [] = {

& Derive::f ()

& Base::g ()

}

As you can see from the vtable of the above two classes, the first item in Derive's vtable overrides the first item of the Base class vtable. As long as the subclass overrides the virtual function of the base class, the corresponding item of the subclass vtable will change the vtable entry of the parent class. This process is handled automatically by the compiler, and the vtable content of each class is placed in the data segment.

3. Who tied the object to vtable?

The above code only defines the content of the vtable for each class, but we know that an object with a virtual function has a vtable pointer inside it, pointing to the vtable, so when was it specified? Just look at the assembly code of the constructor and you can see at a glance:

The compiled code for the Base::Base () function is as follows:

[cpp] view

Plaincopyprint?

_ ZN4BaseC1Ev:

.LFB6:

.cfi _ startproc

.cfi _ personality 0x0,__gxx_personality_v0

Pushl ebp

.cfi _ def_cfa_offset 8

Movl esp, ebp

.cfi _ offset 5,-8

.cfi _ def_cfa_register 5

Movl 8 (% ebp),% eax

Movl $_ ZTV4Base+8, (eax)

Popl ebp

Ret

.cfi _ endproc

The symbol ZN4BaseC1Ev is the internal symbolic name of the C++ function Base::Base (), which can be restored using c++flit. The class in C++ can define data members and function members. But when converted to the assembly level, what is really stored in each object is the data member, as well as the virtual function table.

In the Base class above, since there are no data members, it has only one vtable pointer. Therefore, the definition of the Base class can be written as the following corresponding C code:

[cpp] view

Plaincopyprint?

Struct Base {

Unsigned long * * vtable

}

The two most critical sentences in the constructor are:

Movl 8 (% ebp),% eax

Movl $_ ZTV4Base+8, (eax)

$_ ZTV4Base+8 is the starting position of the virtual function table of the Base class, so the corresponding C code for the constructor is as follows:

[cpp] view

Plaincopyprint?

Void Base::Base (struct Base * this)

{

This- > vtable = & Base_vtable

}

Similarly, the constructor of the Derive class is as follows:

[cpp] view

Plaincopyprint?

Struct Derive {

Unsigned long * * vtable

}

Void Derive::Derive (struct Derive * this)

{

This- > vtable = & Derive_vtable

}

4. The most critical step in implementing runtime polymorphism

The value of vtable set in the constructor is obviously the same in all objects of the same type and will never change. The following is the assembly code generated by the main function, which shows how C++ uses vtable to implement run-time polymorphism.

[cpp] view

Plaincopyprint?

.globl main

.type main, @ function

Main:

.LFB3:

.cfi _ startproc

.cfi _ personality 0x0,__gxx_personality_v0

Pushl ebp

.cfi _ def_cfa_offset 8

Movl esp, ebp

.cfi _ offset 5,-8

.cfi _ def_cfa_register 5

Andl $- 16,% esp

Subl $32,% esp

Leal 24 (% esp),% eax

Movl eax, (esp)

Call _ ZN6DeriveC1Ev

Leal 24 (% esp),% eax

Movl eax, 28 (esp)

Movl 28 (% esp),% eax

Movl (% eax),% eax

Movl (% eax),% edx

Movl 28 (% esp),% eax

Movl eax, (esp)

Call *% edx

Movl $0,% eax

Leave

Ret

.cfi _ endproc

Andl $- 16,% esp

Subl $32,% esp

These two sentences allocate space on the stack for the local variables d and bp, that is, the following statements:

Derive d

Base * pb

Leal 24 (% esp),% eax

Movl eax, (esp)

Call _ ZN6DeriveC1Ev

Esp+24 is the first address of the variable d, press it on the stack first, and then call the constructor of d, which is translated into C language as follows:

Derive::Dervice & d

Leal 24 (% esp),% eax

Movl eax, 28 (esp)

This is actually assigning the value of & d to pb, that is:

Pb = & d

The most critical code is the following paragraph:

[cpp] view

Plaincopyprint?

Movl 28 (% esp),% eax

Movl (% eax),% eax

Movl (% eax),% edx

Movl 28 (% esp),% eax

Movl eax, (esp)

Call *% edx

The sentence translated into C language is also vivid:

Pb- > vtable [0] (bp)

The compiler will remember that the f virtual function is placed in item 0 of vtable, which is the compile-time information.

5. Summary

A lot of details about compilers and C++ are omitted here because of the need for ease of use. You can see the following information from the compiled code above:

1. Each class has its own vtable structure, and the compiler will fill in their virtual function table correctly.

two。 When the object is constructing the function, set the vtable value to the virtual function table of this class

3. Calling a virtual function during a pointer or reference is achieved by object- > vtable plus the offset of the virtual function.

Of course, this is just the implementation of Gmail +, which is slightly different from that of VC++, but the principle is the same.

At this point, I believe you have a deeper understanding of the "virtual function in C++". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 227

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report