The C++ override keyword is used in detail

  • 2020-06-03 07:42:32
  • OfStack

C++ override literally means overwrite, but in fact in C++ it overwrites one method and overrides it for a different purpose. In our C++ programming process, the most familiar is the implementation of the interface method, in the interface 1 generally just declare the method, and we need to implement the implementation of the interface declaration of all methods. Another typical application is the method that may be overridden by a subclass in inheritance.

Public inheritance consists of two parts: 1 is interface (interface) and 2 is implementation (implementation).

For example, the inheritance of several member functions of Person class:


class Person{ 
public: 
 virtual void Eat() const = 0; // 1)  Pure virtual function  
 virtual void Say(const std::string& msg); // 2)  Ordinary virtual function  
 int Name() const; // 3)  A virtual function  
}; 
 
class Student: public Person{ ... }; 
class Teahcer: public Person{ ... }; 

1. Pure virtual functions

A pure virtual function that inherits the interface of a member function of the base class must be overridden in a derived class:


Person *s1 = new Student; 
s1->Eat(); // calls Student::Eat 
 
Person *t1 = new Ellipse; 
t1->Eat(); // calls Teacher::Eat 

To call Eat() of the base class, add the class scope operator ::


s1->Person::Eat(); // calls Person::Eat 

2. Ordinary virtual functions

A normal virtual function, corresponding to a default implementation defined in the base class (default implementation), inherits the interface and default implementation of the base class member function, and is overridden by the derived class at its own option.

In fact, it is dangerous to allow plain virtual functions to inherit both the interface and the default implementation. As follows, CarA and CarB are two types of Car and both operate in exactly the same way.


class Car{ 
public: 
 virtual void Run(const Car& destination); 
}; 
class CarA: public Car{ ... }; 
class CarB: public Car{ ... }; 

This is typical of object-oriented design, where two classes share one feature, Run, and Run can be implemented in the base class and inherited by two derived classes.

Now add a new aircraft model CarC, its flight mode is not the same as CarA, CarB, if accidentally forget to rewrite the new Fly function in CarC


class CarC: public Car{ 
 ... // no fly function is declared 
}; 

Then the Run function in CarC is called, which is Car::Run, but CarC does not run in the same way as the default


Car *pa = new CarC; 
pa->Run(Beijing); // calls Car::Run! 

That being said, it is dangerous for ordinary virtual functions to inherit both the interface and the default implementation, and it is best to implement the default behavior (behavior) in the base class, but only if required by the derived class.

Method 1:

One is pure virtual + default implementation, because it is pure virtual, only the interface is inherited, and the default implementation is not. For a derived class to use this default implementation, it must explicitly call:


class Car{ 
public: 
 virtual void Run(const Run& destination) = 0; 
}; 
 
void Car::Run(const Airport& destination) 
{ 
 // a pure virtual function default code for Run an Car to the given destination 
} 
 
class CarA: public Car{ 
public: 
 virtual void Run(const Car& destination) { Car::Run(destination); } 
}; 

So in the derived class CarC, even if 1 accidentally forgets to override the Run function, it does not call the default implementation of Car


class CarC: public CAr{ 
public: 
 virtual void Run(const Car& destination); 
}; 
 
void CarC::Run(const Car& destination) 
{ 
 // code for Run a CarC Car to the given destination 
} 

Method 2:

As you can see, the key to the above problem is that 1 accidentally forgot to override the Run function in the derived class CarC, and C++11 USES the keyword override to avoid such "1 carelessness".

Non-virtual function:

The non-virtual member function does not have the virtual keyword, which means that the derived class inherits not only the interface, but also a mandatory implementation (mandatory implementation). Since it inherits a mandatory implementation, there is no need to redefine the member function inherited from the base class in the derived class, as follows:

Call the Name function with a pointer, and both are called Person::Name()


Student s1; // s1 is an object of type Student 
 
Person *p= &s1; // get pointer to s1 
p->Name(); // call Name() through pointer 
 
Student *s= &s1; // get pointer to s1 
s->Name(); // call Name() through pointer 

What if you redefine the member function Name, which is inherited from the base class, in a derived class?


class Student : public Person{ 
public: 
 int Name() const; // hides Person::Name 
}; 
 
p->Name(); // calls Person::Name() 
s->Name(); // calls Student::Name() 

At this point, the redefined member function in the derived class "hides" (hide) the member function inherited from the base class

This is because non-virtual functions are "statically bound", p is declared as a pointer to Person*, and non-virtual functions called through p are all in the base class, even if p points to derived classes.

As opposed to "static binding" is the "dynamic binding" of virtual functions, that is, whether p is declared as Person* or Student*, the virtual function it calls depends on the type of object p actually points to

Rewrite (override)

Add the override keyword to your program to avoid the error of forgetting to override a virtual function in a derived class

Here are four mistakes that are easy to make when overwriting virtual functions


Person *s1 = new Student; 
s1->Eat(); // calls Student::Eat 
 
Person *t1 = new Ellipse; 
t1->Eat(); // calls Teacher::Eat 
0

In a derived class, overriding an implementation (override) inherited from a member function of the base class (implementation) meets the following conditions:

1 Virtual: In the base class, member functions are declared virtual (virtual)

In both base and derived classes, the return type and exception specification of the member function (exception specification) must be compatible

In both base and derived classes, the member function name, parameter type, constant attribute (constness), and reference qualifier (reference qualifier) must be identical

With so many constraints, virtual function overrides like the above code are extremely prone to error due to one careless error

The override keyword in C++11 can be explicitly declared in derived classes, which member functions need to be overridden, and if not, the compiler will report an error.


Person *s1 = new Student; 
s1->Eat(); // calls Student::Eat 
 
Person *t1 = new Ellipse; 
t1->Eat(); // calls Teacher::Eat 
1

Person *s1 = new Student; 
s1->Eat(); // calls Student::Eat 
 
Person *t1 = new Ellipse; 
t1->Eat(); // calls Teacher::Eat 
2

1) Public inheritance

Pure virtual function = > Inherited is: Interface (interface) Ordinary virtual function = > Interface + default implementation (default implementation) Non-virtual member function = > Inherited is: interface + mandatory implementation (mandatory implementation)

2) Do not redefine a non-virtual function that inherits from the base class (never redefine an inherited ES176en-ES177en function)

3) After declaring the function to be overridden, add the keyword override
In this way, even if you accidentally omit one of the harsh conditions of virtual function overrides, you can quickly correct the errors through compiler error reporting.

The following points should be noted in use:
(1) The logo of the covered method must be exactly matched with the logo of the covered method to achieve the effect of coverage;
(2). The return value of the overridden method must be the same as the return value of the overridden method;
(3). The exception thrown by the overridden method must be the same as the exception 1 thrown by the overridden method, or a subclass thereof;
(4). The overridden method cannot be private, otherwise only a new method is defined in its subclass and it is not overridden.


Related articles: