How to use polymorphism and virtual functions in C++

This article will introduce you to the principles of using polymorphism and virtual functions in C++. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

1. Why virtual is needed

According to Java's way of thinking, polymorphism can be achieved after inheritance and upcasting. But it seems that orz is not possible in C++. Consider this situation:

As a bonus for this article, you can receive free C++ learning information package, technical videos/codes, and 1,000 interview questions from major manufacturers, including (C++ basics, network programming, database, middleware, back-end development, audio and video development, Qt development) ↓↓↓ ↓↓↓See below↓↓Click at the bottom of the article to get it for free↓↓

#include<iostream>
using std::cout;
using std::endl;
class A{
public:
  void f() const{
    cout<<"class A's function"<<endl;
  }
};
class B : public A{
public:
  void f() const{
    cout<<"class B's function"<<endl;
  }
};
int main(){
  B b;
  A *ptr_a = &b;
  A &ref_a = b;
  ptr_a->f();//print: class A's function
  ref_a.f();//print: Class A's function
}

When using a base class pointer or reference to call a function of a derived class object, we find that the program is still calling the function of the base class. To solve this situation, we need to introduce the virtual keyword and modify class A in the above code as follows , the output in main becomes the output of f() in class B.

class A{
public:
  virtual void f() const{
    cout<<"class A's function"<<endl;
  }
};

So why doesn't Java need it? Because the virtual keyword will increase the time and space occupied by some operations of this class when implementing functions, C++ leaves the optimization decision-making power for this part of the occupation to the programmer to achieve possible efficiency improvements; and Java has a built-in virtual mechanism , does not increase efficiency, but simplifies programming. (For the specific mechanism of virtual, it is recommended to refer to Thinking in C++)

There are two points to note:

  • First, when a base class pointer is used to point to a derived class, functions added in the derived class cannot be directly called through the base class pointer (there is no virtual function with the same name in the base class) unless the base class pointer is cast to a derived class pointer.
  • Second, derived class objects can only be called through base class pointers or references. If we pass a derived class object to a base class object by value, the object is really cut into a base class object and does not have The contents of any derived class.

2. Pure virtual functions and abstract classes

When designing a class, we often hope that the base class will only serve as an interface for the derived class and be inherited and implemented without creating a base class object. In this case, we can define a pure virtual function in the base class to make it an abstract class. The syntax for defining a pure virtual function is to add =0 to the declaration of a virtual function. For example: virtual void f() = 0; Note: When inheriting an abstract class, all its pure virtual functions must be implemented, otherwise the inherited class is also an abstract class.

Under normal circumstances, we will not implement pure virtual functions in base classes, but C++ provides a mechanism to implement pure virtual functions. This method allows us to define a public code so that derived classes can share it.

class A{
public:
  virtual void do() = 0; 
};
/*
*纯虚函数不能作为inline函数实现,要放在类外!
*/
void A::do(){
  //一些公共代码
}
class B : public A{
public:
  void do() {
    A::do();
    //其他代码
  }
};

3.Constructor and virtual function

As mentioned above, when defining a virtual function, some extra work needs to be done, and the code to complete this work is actually secretly inserted into the beginning of the class constructor. So there is a question, what will happen if we call a virtual function in the constructor? The answer is that the local version of this virtual function will be called, that is, the virtual function mechanism does not work in the constructor.
In addition, constructors cannot be defined as virtual functions.

4. Virtual destructor and pure virtual destructor

Constructors cannot be defined as virtual functions, but destructors can, and often are, defined as virtual functions.

#include<iostream>
using namespace std;
class Base1{
public:
  ~Base1(){cout<<"~Base1()"<<endl;}
};
class Base2{
public:
  virtual ~Base2(){cout<<"~Base2()"<<endl;}
};
class Derived1 : public Base1{
public:
  ~Derived1(){cout<<"~Derived1()"<<endl;}
};
class Derived2 : public Base2{
public:
  ~Derived2(){cout<<"~Derived2()"<<endl;}
};
int main(){
  Base1* pd1 = new Derived1();
  Base2* pd2 = new Derived2();
  delete pd1;
  delete pd2;
}

Console output for the above code:

~Base1()
~Derived2()
~Base2()

The above code exposes the impact of not defining the destructor as a virtual function when using polymorphism. This error will not crash the program immediately, but it will leak memory unknowingly.

5. Application of pure virtual destructor

Sometimes, we need to define an abstract class, but there happens to be no other pure virtual function. At this time, we might as well define the destructor as pure virtual, because the destructor as a base class is required to be a virtual function. Further defining it as a pure virtual function doesn't make much difference. The only thing to note is that when defining a pure virtual destructor, you must provide a function body for it, as follows.

class A{
public:
  virtual ~A() = 0;
};
A::~A(){ }

class B:public A{
//不一定需要重定义析构函数,根据需要
}

Also note that in the destructor, the virtual mechanism does not exist, which can be experienced through the following code.

#include<iostream>
using namespace std;
class Base{
public:
  virtual ~Base(){cout<<"~Base()"<<endl;f();}
  virtual void f(){cout<<"Base::f()"<<endl;}
};
class Derived : public Base{
public:
  ~Derived(){cout<<"~Derived()"<<endl;}
  void f(){cout<<"Derived::f()"<<endl;}
};
int main(){
  Base * pb = new Derived();
  delete pb;
}

The console output is:

~Derived()
~Base()
Base::f()

The above is a brief introduction to the usage principles of polymorphism and virtual functions in C++. Of course, the detailed use of the above differences must be understood by everyone themselves.

As a bonus for this article, you can receive free C++ learning information package, technical videos/codes, and 1,000 interview questions from major manufacturers, including (C++ basics, network programming, database, middleware, back-end development, audio and video development, Qt development) ↓↓↓ ↓↓↓See below↓↓Click at the bottom of the article to get it for free↓↓

Guess you like

Origin blog.csdn.net/m0_60259116/article/details/133028156