In depth understanding of virtual keywords in c++

  • 2020-04-02 02:12:53
  • OfStack

1. What are the main functions of virtual keywords?
Dynamic binding is not the default for function calls in c++. To trigger dynamic binding, two conditions must be met: first, to be specified as a virtual function; Second, through a reference or pointer to a base class type.
Thus, virtual is primarily about dynamic binding.

2. In what cases can virtual keywords be used?
Virtual is used to define class functions and apply to virtual inheritance.

Friend function constructor static static function cannot be decorated with virtual keyword;
General member functions and destructors can be decorated with virtual keywords;

3. Effects of virtual functions


class GrandFather
{
public:
 GrandFather() {}
 virtual void fun()
 {
  cout << "GrandFather call function!" << endl;
 }
};
class Father : public GrandFather
{
public:
  Father() {}
  void fun()
  {
   cout << "Father call function!" << endl;
  }
};

class Son : public Father
{
public:
 Son() {}
 void fun()
 {
  cout << "Son call function!" << endl;
 }
};
void print(GrandFather* father)
{
 father->fun();
}
int _tmain(int argc, _TCHAR* argv[])
{
 Father * pfather = new Son;
        pfather->fun();
        GrandFather * pgfather = new Father;
        print(pgfather);
 return 0;
}

The output is Son call function
            Father call the function

4. Virtual inheritance
As long as the base function defines virtual, the function of the inherited class also has virtual properties
That is, GrandFather Father Son defines virtual void fun() at the same time as GrandFather one defines the virtual void fun effect

5. Virtual destructor


class GrandFather
{
public:
 GrandFather() {}
 virtual void fun()
 {
  cout << "GrandFather call function!" << endl;
 }
 ~GrandFather() 
 {
  cout << "GrandFather destruction!" << endl;
 }
};
class Father : public GrandFather
{
public:
 Father() {}
 void fun()
 {
  cout << "Father call function!" << endl;
 }
 ~Father()
 {
  cout << "Father destruction!" << endl;
 }
};

class Son : public Father
{
public:
 Son() {}
 void fun()
 {
  cout << "Son call function!" << endl;
 }
  ~Son()
 {
  cout << "Son destruction!" << endl;
 }
};
void print(GrandFather* p)
{
 p->fun();
}
int _tmain(int argc, _TCHAR* argv[])
{
 Father * pfather = new Son;
 delete pfather;
 return 0;
}

The above code output: Father destruction!
                                                        GrandFather destruction!
The constructor for Son is executed, and the destructor for Son is not executed, so the destructor for GrandFather is set to virtual
Then output: Son destruction!
              Father Destruction!
              GrandFather destruction!

6. Pure virtual functions
Pure virtual function is defined as follows:


class GrandFather
{
public:
 GrandFather() {}
 virtual void fun() = 0
 {
  cout << "GrandFather call function!" << endl;
 }
 virtual ~GrandFather() 
 {
  cout << "GrandFather destruction!" << endl;
 }
};

Pure virtual functions provide overridden interfaces for descendant classes, but the version in this class is never called.
Classes that contain (or continue to contain) one or more pure virtual functions are abstract base classes, which cannot be instantiated!
An inheritance class can be instantiated only if it overrides the interface


7. Virtual inheritance
Virtual inheritance mainly solves the problems caused by cross inheritance. Here is a reference to the article c++ virtual inheritance.
Here's an example


class GrandFather
{
public:
 GrandFather() {}
 void fun()
 {
  cout << "GrandFather call function!" << endl;
 }
 virtual ~GrandFather() 
 {
  cout << "GrandFather destruction!" << endl;
 }
};
class Father1 : public GrandFather
{
public:
 Father1() {}
 void fun()
 {
  cout << "Father call function!" << endl;
 }

};
class Father2 : public GrandFather
{
public:
 Father2() {}
 void fun()
 {
  cout << "Father call function!" << endl;
 }
};

class Son : public Father1, public Father2
{
public:
 Son() {}
 //void fun()
 //{
 // cout << "Son call function!" << endl;
 //}
};
void print(GrandFather* p)
{
 p->fun();
}
int _tmain(int argc, _TCHAR* argv[])
{
 Son* son = new Son;
 son->fun();
 return 0;
}

An error is reported when compiling that access to fun is not clear
The problem can be solved if the Father1 and the Father2 inherit the GrandFather with virtual inheritance

Virtual functions in constructors and destructors
If a virtual function is called in a constructor or destructor, the version defined for the constructor or destructor's own type is run


9. Virtual function implementation mechanism
We will discuss the implementation mechanism of virtual functions later.

Nodule 10.
About the usage of virtual keyword summary as above, there is an error or summary is not in place, please help me point out!

Example 11.


class classA
{
 public:
 classA()
 {
  clear();
 }
 virtual ~classA()
 {
 }
 void clear()
 {
  memset(this , 0 , sizeof(*this));
 }
 virtual void func()
 {
  printf("funcn");
 }
};
class classB : public classA
{
};
int main(void)
{
 classA oa;
 classB ob;
 classA * pa0 = &oa;
 classA * pa1 = &ob;
 classB * pb = &ob;
 oa.func(); // 1
 ob.func(); // 2
 pa0->func(); // 3
 pa1->func(); // 4
 pb->func(); // 5
 return 0;
}

To add an example, the output of this program is in order
func
func
error
func
func

Talk about my understanding, when
ClassA oa.
Oa. Func ();
There is no dynamic calling procedure, so although func is a virtual function, function calls are not accessed through virtual tables, so even if


memset(this , 0 , sizeof(*this));

It doesn't matter if you can't find the virtual table address
Execute classB ob; Note that memset is the address of classA and all the virtual tables of ob exist
That is, accessing the func function of oa through a pointer or a reference (dynamic binding) (which requires access from a virtual table) will cause an error
Access the func and functions of ob without error, whether static or dynamic


When you change the classB code to the following


class classB : public classA
<PRE style="FONT-WEIGHT: bold" class=cpp name="code">{</PRE><PRE style="FONT-WEIGHT: bold" class=cpp name="code">        classB()
 {
  clear();
 }
 virtual ~classB()
 {
 }
 void clear()
 {
     memset(this , 0 , sizeof(*this));
 }</PRE><BR>
<PRE></PRE>
<PRE style="FONT-WEIGHT: bold" class=cpp name="code">};</PRE> The output is 

func
func
error
error
error


Related articles: