Describes the underlying virtual function classes for inheritance and polymorphism in C + +

Source: Internet
Author: User
This article mainly introduces to you about C + + in the inheritance and polymorphism of the underlying virtual function class data, the text through the sample code introduced in very detailed, to everyone's study or work has a certain reference learning value, the need for friends below with small to learn together.

Objective

This article mainly introduces about C + + in the inheritance and polymorphism of the underlying virtual function of the relevant content, shared out for everyone to refer to the study, the following words do not say, come together to see the detailed introduction bar.

virtual function class

Inheritance we often refer to virtual inheritance, and now we explore this kind of virtual function, virtual function class member function in front of the virtual keyword, then this member function is called virtual function, do not underestimate this virtual function, he can solve the inheritance of many thorny problems, and for polymorphism that he is more important, no it is not polymorphic , so this knowledge point is very important, as well as the virtual function table described in the following is extremely important, we must seriously understand ~ Now the concept of virtual function has come up with a concept, that is, rewrite (overwrite), when the subclass of the definition of a parent class is exactly the same virtual function, This function of the subclass is called the override (also called overwrite) of this virtual function of the parent class. Here is the virtual function table, which will be described later, rewrite is the virtual function inside the subclass of the table of the overridden parent class function address all changed to the address of the subclass function.

Pure virtual function

After the parameter of the member function is written with = 0, the member function is a pure virtual function. Classes that contain pure virtual functions are called abstract classes (also called interface classes)

An abstract class cannot instantiate an object. When a pure virtual function is redefined in a derived class, the derived class can instantiate the object.

See an example:


Class Person {   virtual void Display () = 0;//pure virtual function protected:   string _name;   name};  Class student:public person {};

First summarize the concept:

1. Derived classes override the virtual functions of the base class to implement polymorphism, requiring the function name, parameter list, and return value to be exactly the same. (excluding covariance)

2. A virtual function is defined in a base class that always retains the attributes of the virtual function in the derived class.

3. Only member functions of a class can be defined as virtual functions.

4. Static member functions cannot be defined as virtual functions.

5. If you define a virtual function outside of a class, you can only add virtual when declaring a function, and you cannot add virtual when you define a function outside of the class.

6. Do not call virtual functions inside constructors and destructors, in constructors and destructors, objects are incomplete, and undefined behavior can occur.

7. It is best to declare the destructor of the base class as a virtual function. (Why?) In addition, the destructor is special, because the destructor of the derived class is different from the destructor name of the base class, but it is an overlay, this is because the compiler has made a special deal with the constructor.

8. The constructor cannot be a virtual function, although operator= can be defined as a virtual function, but it is best not to define operator= as a virtual function, because it is easy to confuse when used easily.


The above concept may be asked, why do we do this? This content in the next knowledge can be found in the answer ~ Well then we today's protagonist virtual function appeared!!!!

What is a virtual function table, we write a program, a monitoring window to know.

The following is a class with a virtual function:


#include <iostream> #include <windows.h> using NAMESPACESTD;  Class Base {public:    virtual void func1 ()    {}     virtual void Func2 ()    {}  private:    inta;};  void Test1 () {    Base b1;}  int main ()  {    Test1 ();    System ("pause");    Return0; }

We're opening B1 's surveillance window now.

There is a _vfptr, and this _vfptr point is our protagonist, the virtual function table. A few people will know, whether it is a single inheritance or multiple inheritance even our diamond inherited virtual function table will have a different form, virtual function table is a very interesting thing.

Let's look at a single-inheritance memory pattern.

Take a closer look at the following code:


#include <iostream> #include <windows.h> using namespace std;   Class Base {public:    virtual void func1 ()    {      cout<< "base::func1" << Endl;    }     virtual void Func2 ()    {      cout<< "base::func2" << Endl;    }  Private:    inta;};  Class Derive:public Base {public:    virtual void func1 ()    {      cout<< "derive::func1" << Endl;    }     virtual void func3 ()    {      cout<< "derive::func3" << Endl;    }     virtual void Func4 ()    {      cout<< "Derive::func4" << Endl;    }  Private:    int b;};

For the derive class, what do we think of its imaginary table?

First of all the subclasses of the fun1() parent class fun1() , the virtual table is a subclass, the fun1() next parent class, the fun2() subclass fun3() , fun4() are virtual functions, so the virtual table will have 4 elements, respectively, the subclass fun1() , the parent class fun2() , Subclass fun3() , Subclass fun4() . And then we pull up the Watch window to see what we think is right?

I expected to be seen fun1() , fun2() , fun3() , fun4() the virtual function table, but there are only two monitoring Windows, fun1() fun2() , we are wrong????

This is not the case, only self-reliable, I think there is a problem with the compiler, then we have to explore it ourselves. But before we explore, we have to implement a function that can print a table of virtual functions.


typedef void (*FUNC) (void); void Printvtable (int* VTable) {    cout<< "virtual table address" <<VTable<< Endl;     for (inti = 0; Vtable[i]! = 0; ++i)    {      printf ("%d virtual function address:0x%x,->", i,vtable[i]);      Func f = (func) vtable[i];      f ();    }     cout<< Endl; }   int Main () {    Derive D1;    Printvtable ((int*) (* (int*) (&D1));    System ("pause");    Return0; }

The reason for his explanation:


Let's use this function, the function code is as follows:


Single-Inherit class Base {public:  virtual void func1 ()  {   cout << "base::func1" << Endl;  }   virtual void Func2 ()  {   cout << "Base::func2" << Endl;  }  Private:  int A;};  Class Derive:p ublic Base {public:  virtual void func1 ()  {   cout << ' derive::func1 ' << endl;
  }   virtual void func3 ()  {   cout << "derive::func3" << Endl;  }   virtual void Func4 ()  {   cout << "Derive::func4" << Endl;  }  Private:  int b;}; typedef void (*FUNC) (void); void Printvtable (int* VTable) {    cout<< "virtual table address" <<VTable<< Endl;      for (inti = 0; Vtable[i]! = 0; ++i)    {      printf ("%d virtual function address:0x%x,->", i,vtable[i]);      Func f = (func) vtable[i];      f ();    }      cout<< Endl; }     int Main () {    Derive D1;    Printvtable ((int*) (* (int*) (&D1)); Focus    System ("pause");    Return0; }

Here I am going to talk about this communication, note that the communication here is not good understanding, should be carefully "taste."


Printvtable ((int*) (* (int*) (&D1));

First of all, we must get D1 's first address, turn it into int*, let him read the first 4 bytes of content (that is, to the address of the virtual table), and then to the address of the reference, we have the virtual table of the first address of the content (the virtual table stored in the first function address), But at this point, the type of the variable is an int, cannot pass in the function, so we re-int* him a forced type conversion, so we passed the parameter, start the function execution, we are all in a controlled situation with the use of strong turn, use strong turn you have to be particularly aware of the memory distribution structure.

Finally, let's take a look at the output:



Did you print the right thing? Let's verify that:

Here we find the address of the virtual table through the &D1 's first address, and then access the address to see the contents of the virtual table, verifying that the function we wrote ourselves is correct. (Here vs has a bug that when you first print a virtual table The program may crash, don't worry about you rebuilding the solution, run it again.) Because when you first print is your virtual table the last place may not put 0, so you may not stop and then crash. We can see that D1 's virtual table is not what it looks like in a monitor, so sometimes vs has bugs, don't trust others, or be reliable. hahaha, flatter yourself ~

Let's take a look at the multi-inheritance memory pattern.

Explore the single inheritance, we look at multiple inheritance, we still through the code debugging method to explore the object model

Look at the following code:


Class Base1 {public:virtual void func1 () {cout << ' base1::func1 ' << Endl;  } virtual void Func2 () {cout << "base1::func2" << Endl; } Private:int B1;  };  Class Base2 {public:virtual void func1 () {cout << ' base2::func1 ' << Endl;  } virtual void Func2 () {cout << "base2::func2" << Endl; } Private:int B2;   }; Class Derive:public Base1, public Base2 {public:virtual void func1 () {cout << ' derive::func1 ' << Endl  ;  } virtual void func3 () {cout << "derive::func3" << Endl; } private:int D1;  }; typedef void (*FUNC) ();   void Printvtable (int* VTable) {cout << "virtual table address >" << VTable << Endl; for (int i = 0; Vtable[i]! = 0;   ++i) {printf ("%d virtual function address:0x%x,->", I, vtable[i]);   Func f = (func) vtable[i];  f (); } cout << Endl;  } void Test1 () {Derive D1;  Base2 virtual function table after object Base1 int* VTable = (int*) (* (int*) &d1);  Printvtable (VTable); int* VTable2 = (int *) (* (int*) &d1 + sizeof (BASE1)/4); Printvtable (VTable2);  } int main () {Test1 ();  System ("pause"); return 0; }

Now we know there will be two virtual function tables, respectively, BASE1 and Base2 's virtual function table, but! What about the functions in our subclasses fun3() ? Is it put in Base1 or Base2 or do you create a virtual function table? Let's start by adjusting the Watch window:


The monitoring window is not reliable .... FUN3 () was not found at all. Let's look directly at the printed virtual function table.


Now it is clear that fun3() in Base1 's virtual function table, and BASE1 is the first class to inherit, well now we remember this conclusion, when it comes to multiple inheritance, the virtual function of the subclass will exist in the virtual function table of the class that inherits first. Remember it!

Let's look at the multi-inheritance object model:


Now let's end up with so many of the concepts I've listed above now I'll explain why.

1. Why can't a static member function be defined as a virtual function?

Because the static member function is a resource shared by everyone, but this static member function does not have this pointer, and the virtual function changes only the object can be transferred to, but the static member function does not need the object can be called, so there is a conflict.

2. Why not call virtual functions in constructors and destructors?

The reason why a virtual function is not suitable for a constructor is that there is no memory allocated for the virtual function table during the construction of the object. Therefore, this call is also a violation of the code called after the first instantiation of the destructor is not applicable to the virtual function is: The General destructor first destructor, when you call an overriding function in the parent class, the fun() virtual function table is a subclass of the fun() function, this time has been sub-class has been broken down, It will not be called when you call it.

Now I'm writing the last point of knowledge, why is it best to declare the destructor of the base class as a virtual function??

Now let's write an example, we all know that the normal instantiation of the object and then release is no problem, but now I give a special case:

We all know that a pointer to a parent class can point to a subclass, and now we're going to use a pointer to the parent class to new the object of a subclass.


Polymorphic destructor class Base {public:  virtual void func1 ()  {   cout << "base::func1" << Endl;  }   virtual void Func2 ()  {   cout << "Base::func2" << Endl;  }   Virtual ~base ()  {   cout << "~base" << Endl;  }  Private:  int A;};  Class Derive:p ublic Base {public:  virtual void func1 ()  {   cout << ' derive::func1 ' << endl;
  }  Virtual ~derive ()  {   cout << "~derive" << Endl;  } private:  int b;};  void Test1 () {  base* q = new Derive;  Delete q; } int main () {  Test1 ();  System ("pause");  return 0; }

There may be a lot of the next one to say, so it may be understandable that the dues will be a little harder.

Notice here that I let the parent's destructor not be a virtual function (remove virtual), let's look at the output:


Here it does not call the destructor of the subclass, because he is a parent class type pointer, so it can only call the parent class destructor, do not have access to the child class destructor, this call method can cause memory leak, so this is flawed, but C + + is not allowed to have a flaw, he will find a way to solve this problem, This applies to the polymorphism we're going to talk about next time. Now let's add virtual to the parent destructor and let it go back to the virtual function, and we'll run the program again:


Eh The virtual function of a subclass is called again, what happens here?? Come to our old way to open the Watch window.


In this case, polymorphic, polymorphism can be simply summed up as "one interface, multiple methods", the program at runtime to determine the function of the call, it is the core concept of object-oriented programming domain. This is our next blog dedicated to summarizing polymorphism.

Of course, the knowledge point of virtual function is not so much, this may just be the tip of the iceberg, for example, what is the virtual function table of diamond inheritance? And what does a diamond virtual inheritance look like? I'll write a blog to discuss the Diamond inheritance. Virtual function Table We should already know what it is, and also know that the application of single inheritance and multi-inheritance, these should be enough, these are all for you to better understand the inheritance and polymorphism, of course, you must be divided clearly rewrite, redefine, overloaded their respective meaning is what. This piece may be a bit around, but we have to master 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.