Deep understanding of C++ virtual virtual function usage

  • 2020-10-23 21:08:28
  • OfStack

1. virtual modifies a function in a base class that is overridden by a derived class:


#include
using namespace std;
class A{
public:
 virtual void display(){ cout<<"A"<<ENDL; }
 };
class B : public A{
public:
  void display(){ cout<<"B"<<ENDL; }
 };
void doDisplay(A *p)
{
p->display();
delete p;
}
int main(int argc,char* argv[])
{
doDisplay(new B());
return 0;
}

This code prints B, but when virtual is removed from the A class, it prints A.

When there is no virtual in the base class, the compiler considers p to be an object of the A class at compile time, and calls the methods of the A class naturally.

But with the addition of virtual, the dispaly method becomes virtual, so that when invoked the compiler will see whose instantiated object is being invoked, and the polymorphic effect is achieved.

That is, when a base class has a virtual method overridden by a derived class, using the base class pointer to the derived class object, calling the method will actually call the last implemented method of the derived class

2. The derived class virtual inherits the base class


#include
using namespace std;
class Person{
 public: Person(){ cout<<"Person structure "<<ENDL; }
  ~Person(){ cout<<"Person destructor "<<ENDL; }
};
class Teacher : virtual public Person{
 public: Teacher(){ cout<<"Teacher structure "<<ENDL; }
  ~Teacher(){ out<<"Teacher destructor "<<ENDL; }
};
class Student : virtual public Person{
 public: Student(){ cout<<"Student structure "<<ENDL; }
  ~Student(){ cout<<"Student destructor "<<ENDL; }
};
class TS : public Teacher, public Student{
public:  TS(){ cout<<"TS structure "<<ENDL; }
   ~TS(){ cout<<"TS destructor "<<ENDL; }
};
int main(int argc,char* argv[])
{
TS ts;
return 0;
}

1) The terminal output result of this code is:

[

Person structure
Teacher structure
Student structure
TS structure
TS destructor
Student destructor
Teacher destructor
Person destructor

]

2) When Teacher class and Student class do not have virtual inheritance of Person class, that is, when virtual is removed, the output result of the terminal is:

[

Person structure
Teacher structure
Person structure
Student structure
TS structure
TS destructor
Student destructor
Person destructor
Teacher destructor
Person destructor

]

You can see clearly that this result is obviously not what we expected:

When we construct TS, we need to construct its base classes, which are Teacher and Student. Both the Teacher and Student classes inherit from the Person class. This resulted in two Person classes being instantiated when TS was constructed.

By the same token, the Person class is destructed twice, which is very dangerous, and that leads to the third use of virtual, virtual destructor, virtual inheritance.

3. Virtual destruction and virtual inheritance


#include
using namespace std;
class Person{
 public: Person() {name = new char[16];cout<<"Person structure "<<ENDL;}
 virtual ~Person() {delete []name;cout<<"Person destructor "<<ENDL;}
 private:
  char *name;
  };
class Teacher :virtual public Person{
public:  Teacher(){ cout<<"Teacher structure "<<ENDL; }
  ~Teacher(){ cout<<"Teacher destructor "<<ENDL; }
};
class Student :virtual public Person{
public:  Student(){ cout<<"Student structure "<<ENDL; }
  ~Student(){ cout<<"Student destructor "<<ENDL; }
};
class TS : public Teacher,public Student{
public:  TS(){ cout<<"TS structure "<<ENDL; }
   ~TS(){ cout<<"TS destructor "<<ENDL; }
};
int main(int argc,char* argv[])
{
Person *p = new TS();
delete p;
return 0;
}

1) The operation result of this code is:

[

Person structure
Teacher structure
Student structure
TS structure
TS destructor
Student destructor
Teacher destructor
Person destructor

]

2) But when we remove virtual before destruct in Person class, the running result is as follows:

[

Person structure
Teacher structure
Student structure
TS structure
Person destructor
Program crashes

]

Obviously this is not the program we want, the consequences of the crash are unpredictable, so we must pay attention to the base class before the destructor virtual,

Make it virtual destructor Using virtual functions, virtual inheritance, and virtual destructor in C++ programs is a good practice to avoid many problems.

Virtual destructor:

If a class is used as a base class, it is important that we usually need virtual to decorate its destructor.

If the destructor of the base class is not virtual destructor, only the destructor of the base class is called, and the destructor of the derived class is not called, when we use delete to free the memory occupied by the base class pointer (which actually refers to the object instance of the derived class),

This can cause a memory leak. If the destructor of the base class is virtual destructor, then the destructor of the inheritance tree will be called from the bottom to the top when the delete base class pointer, that is, the destructor of the lowest derived class will be called first,

Then layer by layer up until the pointer declares the type.

Virtual inheritance:

Virtual inheritance is a special concept in multiple inheritance. Virtual base classes have emerged to address multiple inheritance. [Diamond Inheritance]

For example, class D inherits from class B1 and B2, while class B1 and B2 both inherit from class A, so the variables and functions in class A appear twice in class D.

To save memory space, the inheritance of B1 and B2 to A is defined as virtual inheritance, and A becomes the virtual base class. The implementation code is as follows:


class A
 
class B1:public virtual A;
 
class B2:public virtual A;
 
class D:public B1,public B2;

Virtual inheritance is rarely used in 1-like applications, so it tends to be ignored, mainly because multiple inheritance is not recommended and is not commonly used in C++,

Once the multiple inheritance is removed, virtual inheritance completely loses the necessity of existence because it will only reduce the efficiency and take up more space.

Reference links: https: / / www ofstack. com article / 191365. htm


Related articles: