Go to the Summary of virtual functions in C ++

Source: Internet
Author: User

Virtual functions in C ++)

1. Introduction

Virtual functions are used in C ++ to implement polymorphism. The core concept is to access the functions defined by the derived class through the base class. Suppose we have the following class layers:

Class
{
Public:
Virtual void Foo () {cout <"A: Foo () is called" <Endl ;}
};

Class B: public
{
Public:
Virtual void Foo () {cout <"B: Foo () is called" <Endl ;}
};

In this case, we can:

A * A = new B ();
A-> Foo (); // here, although a points to a, the called function (FOO) is B!

This example is a typical application of virtual functions. Through this example, you may have some concepts about virtual functions. It is virtual on the so-called "Deferred Association" or "Dynamic Association". The call of a class function is not determined at the time of compilation, it is determined at the runtime. When writing the code, it cannot be determined whether the base class function or the derived class function is called, so it becomes a "virtual" function.

A virtual function can achieve polymorphism only by means of pointers or references. If the following code is used, it is a virtual function, but it is not a polymorphism:

Class
{
Public:
Virtual void Foo ();
};

Class B: public
{
Virtual void Foo ();
};

Void bar ()
{
A;
A. Foo (); // A: Foo () is called.
}

1.1 Polymorphism

After understanding the meaning of a virtual function, it is easy to consider what is polymorphism. The above class hierarchy is still targeted, but the method used is more complicated:

Void bar (A *)
{
A-> Foo (); // is a: Foo () or B: Foo () called ()?
}

Because Foo () is a virtual function, in bar function, you can only use this code to determine whether a: Foo () or B: is called here :: foo (), but it is certain that if a points to an instance of Class A, A: Foo () is called. If a points to an instance of Class B, then B: Foo () is called.

This same code can produce different effects, known as "polymorphism ".

1.2 What is the use of polymorphism?

Polymorphism is amazing, but what can it do? This proposition is hard to be summarized in one or two sentences. The General C ++ tutorial (or other object-oriented language tutorial) uses a drawing example to demonstrate the usage of polymorphism, I will not repeat this example again. If you do not know this example, you should introduce it in any book. I try to describe from an abstract point of view, and then look back at the example of the drawing, maybe you will be more easy to understand.

In object-oriented programming, data is first abstracted (determining the base class) and inherited (determining the derived class) to form a class hierarchy. When users of this class hierarchy use them, if they still need to write code for the base class when they need the base class, write the code for the derived class when they need the derived class, it means that the class level is completely exposed to the user. If there is any change to the class hierarchy (a new class is added), the user must "know" (write code for the new class ). In this way, the coupling between the class hierarchy and its users is increased. Someone lists this situation as one of the "bad smell" in the program.

Polymorphism can free programmers from this dilemma. Let's look back at the example in 1.1, bar () as the user of the class hierarchy of A-B, it does not know how many classes in this class hierarchy, what is each class called, but the same can work well. When a class C is derived from Class A, bar () does not need to be "known" (modified ). This is entirely due to polymorphism-the compiler generates code for the function to be called at runtime.

1.3 "Dynamic Association"

How does the compiler determine the code of the called function when the virtual function is generated? That is to say, how is a virtual function actually processed by the compiler? In the deep exploration of the C ++ object model [1], Lippman describes several methods. Here we will briefly introduce the "standard" method.

I am talking about the "standard" method, that is, the so-called "vtable" mechanism. When the compiler finds a function declared as virtual in a class, it creates a virtual function table, that is, vtable. Vtable is actually an array of function pointers. Each virtual function occupies a slot of this array. A class has only one vtable, no matter how many instances it has. The derived class has its own vtable, but the vtable of the derived class has the same function arrangement sequence as the vtable of the base class. virtual functions with the same name are placed in the same position of two arrays. When creating a class instance, the compiler adds a vptr field to the memory layout of each instance. This field points to the vtable of the class. Through these methods, the compiler will rewrite this call when it sees a virtual function call. For example in 1.1:

Void bar (A *)
{
A-> Foo ();
}

Will be rewritten:

Void bar (A *)
{
(A-> vptr [1]) ();
}

Because the derived class and the Foo () function of the base class have the same vtable index, and their vptr points to different vtables, this method can be used to determine which Foo () to call at runtime () function.

Although the actual situation is far from that simple, the basic principle is roughly the same.

1.4 overload and override

Virtual functions are always rewritten in the derived class, which is called "Override ". I often confuse the words "overload" and "Override. But with the increasing number of C ++ books, later programmers may not make any mistakes I have made. But I want to clarify:

  • Override refers to the virtual function used by the derived class to override the base class, just as the Foo () function in Class A is rewritten in Class B. The rewritten function must have the same parameter table and return value (the C ++ standard allows different return values. I will briefly introduce this in the "Syntax" section, but few compilers support this feature ). It seems that there is no proper Chinese vocabulary for this word. Some people translate it into "Overwrite", which is more appropriate.
  • Overload conventions are translated as "heavy load ". Compile a function with the same name as an existing function but different from the parameter table. For example, a function can take an integer as a parameter or a floating point as a parameter.
2. Syntax of virtual functions

The sign of the virtual function is the "virtual" keyword.

2.1 use virtual keywords

Consider the following class levels:

Class
{
Public:
Virtual void Foo ();
};

Class B: public
{
Public:
Void Foo (); // No virtual keyword!
};

Class C: Public B // inherit from B, not from!
{
Public:
Void Foo (); // There is no virtual keyword!
};

In this case, B: Foo () is a virtual function, and C: Foo () is also a virtual function. Therefore, it can be said that the virtual function declared by the base class is also a virtual function in the derived class, even if the virtual keyword is no longer used.

2.2 pure virtual functions

The following statement indicates that a function is a pure virtual function:

Class
{
Public:
Virtual void Foo () = 0; // = 0 indicates that a virtual function is a pure virtual function.
};

After a function is declared as pure virtual, the pure virtual function means: I am an abstract class! Don't instantiate me! Pure virtual functions are used to regulate the behavior of derived classes. They are actually called "interfaces ". It tells the user that my Derived classes will all have this function.

2.3 virtual destructor

Destructor can also be virtual, or even pure virtual. For example:

Class
{
Public:
Virtual ~ A () = 0; // pure virtual destructor
};

When a class is intended to be used as the basis class of other classes, its destructor must be virtual. Consider the following example:

Class
{
Public:
A () {ptra _ = new char [10];}
~ A () {Delete [] ptra _;} // non-virtual destructor
PRIVATE:
Char * ptra _;
};

Class B: public
{
Public:
B () {ptrb _ = new char [20];}
~ B () {Delete [] ptrb _;}
PRIVATE:
Char * ptrb _;
};

Void Foo ()
{
A * A = new B;
Delete;
}

In this example, the program may not run as you think. When executing Delete A, there is actually only ::~ A () is called, and Class B's destructor are not called! Is it a little scary?

If the above ::~ Change a () to virtual to ensure that B ::~ B () is also called during Delete. Therefore, the destructor of the base class must be virtual.

Pure virtual destructor have no function, but virtual ones are enough. Generally, when you want to change a class to an abstract class (a class that cannot be instantiated), and this class does not have a suitable function that can be purely virtualized, you can use pure virtual destructor to achieve the goal.

2.4 virtual constructor?

Constructors cannot be virtual.

3. Tips for using virtual functions 3.1 private virtual functions

Consider the following example:

Class
{
Public:
Void Foo () {bar ();}
PRIVATE:
Virtual void bar (){...}
};

Class B: public
{
PRIVATE:
Virtual void bar (){...}
};

In this example, although bar () is private in Class A, it can still appear in the derived class, it can still generate polymorphism like public or protected virtual functions. It is not because it is private, so a: Foo () cannot access B: bar (), or B: bar () to :: bar () override does not work.

The syntax is as follows: a tells B that you 'd better override my bar () function, but do not care how it is used or call this function by yourself.

3.2 call of virtual functions in constructor and destructor

When a class's virtual functions are called in its own constructor and destructor, they become common functions. That is to say, you cannot make yourself "polymorphism" in constructor and destructor ". For example:

Class
{
Public:
A () {Foo () ;}// in any case, a: Foo () is called!
~ A () {Foo ();} // same as above
Virtual void Foo ();
};

Class B: public
{
Public:
Virtual void Foo ();
};

Void bar ()
{
A * A = new B;
Delete;
}

If you want to delete a, it will cause B: Foo () to be called, then you will be wrong. Similarly, in the case of new B, the constructor of A is called, but in the constructor of A, A: Foo () instead of B :: foo ().

3.3 More inherited virtual functions 3.4 when to use virtual functions

When you design a base class, if you find that a function needs to behave differently in a derived class, it should be virtual. From the design perspective, the virtual functions that appear in the base class are interfaces, and the virtual functions that appear in the derived class are the specific implementation of interfaces. In this way, the behavior of objects can be abstracted.

Take the factory method mode in design mode [2] as an example. The factorymethod () of the Creator is a virtual function. After the override function of the derived class is used, different product classes are generated, the generated product class is used by the anoperation () function of the base class. The anoperation () function of the base class operates on the product class. Of course, the product class must also have polymorphism (virtual function ).

Another example is a set operation. Suppose you have a class hierarchy based on class A, and another STD :: vector <A *> to save the instance pointers of different classes in this class hierarchy, So you certainly want to perform operations on the classes in this set, instead of returning each pointer to its original type (derived class), you want to perform the same operation on them. Then we should declare this "same operation" as virtual.

In reality, it is far more than the two examples I mentioned, but the big principle is that I mentioned earlier: "If a function needs to have different performances in a derived class, then it should be virtual ". This sentence can also be reversed: "If you find that the base class provides virtual functions, you 'd better override it ".

 

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.