A brief discussion on three USES of C++ in virtual

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

virtual usage 1


#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 result is polymorphism. 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 virtual usage


#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;
}

The terminal output result of this code is:

[

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

]

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

]

And you can see clearly that this is not what we expected. When we construct TS, we need to construct its base classes, namely Teacher class and Student class. Both the Teacher and Student classes inherit from the Person class. This resulted in the instantiation of two Person classes when constructing TS. By the same token, the Person class is destructed twice during the destructor, which is very dangerous and leads to the third use of virtual, virtual destructor and virtual inheritance.

virtual usage 3


#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;
}

The running result of this code is:

[

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

]

But when we remove virtual before destruct in Person class, the result of the operation is:

[

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 in C++ program using virtual functions, virtual inheritance and virtual destructor is a good habit to avoid a lot of 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 a base class is not virtual destructor, there may be a memory leak if we use delete to free the memory occupied by the base class pointer (which actually refers to an object instance of a derived class), only the destructor of the base class is called, and the destructor of the derived class is not called. If the destructor of the base class is virtual destructor, then the destructor of the inheritance tree is called from bottom to top when the delete base class pointer is invoked, that is, the destructor of the lowest derived class is called first, then layer by layer up to the type declared by the pointer.

Virtual inheritance:

Virtual inheritance is a special concept in multiple inheritance. Virtual base classes have emerged to address multiple 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 can be 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 is often ignored. This is mainly because in C++, multiple inheritance is not recommended and is not commonly used. Once 1 leaves multiple inheritance, virtual inheritance completely loses the necessity of existence because it will only reduce efficiency and take up more space.


Related articles: