At the end of the article, the implementation of non-virtual interface NVI is mentioned, and the virtual function is declared as a protected or private type, which is realized by the template function pattern.
The park friend @KillU looked very carefully, raised a question: virtual function is private type, inherit can? The answer is: it's perfectly possible
5 realization Right and call right
<effective c++> The explanation is: rewrite a virtual function, refers to how to do things (how), and call a virtual function, refers to when to do things (when)
In the NVI or template function pattern, the derived class is allowed to override the virtual function, and the derived class is assigned the "implementation Right"-the implementation of the function function, but the base class still has the "call right"-that is, when the virtual function is called
Sounds very awkward, look at an example, or the implementation of the template function pattern, except that the virtual function is declared private (private)
5.1 Private Virtual functions
Base class AbstractClass and derived classes Concreteclass
classAbstractClass { Public: voidTemplatemethod ();Private: Virtual voidPrimitiveOperation1 (); Virtual voidPrimitiveOperation2 ();};classConcreteclass: PublicAbstractClass {Private: voidPrimitiveOperation1 ()Override; voidPrimitiveOperation2 ()Override;};
The implementation of two virtual functions PrimitiveOperation1,PrimitiveOperation2 and Templatemethod in base class AbstractClass
//implementation of Private member functionvoidAbstractClass::P rimitiveOperation1 () {std::cout<<"Operation1 from AbstractClass!"<<Std::endl;}voidAbstractClass::P rimitiveOperation2 () {std::cout<<"Operation2 from AbstractClass!"<<Std::endl;}//implementation of Non-virtual member functionvoidAbstractclass::templatemethod ()
{PrimitiveOperation1 (); PrimitiveOperation2 ();}
Derived class Concreteclass, overriding two virtual functions PrimitiveOperation1 and PrimitiveOperation2
// Override void "Operation1 from Concreteclass! " " Std::endl;} void "Operation2 from Concreteclass! " " << Std::endl;}
when a virtual function is called through a pointer or reference, the virtual function is either called in the base class or derived class, depending on the class object that is dynamically bound to the pointer or reference
// Call virtual functions in AbstractClass New abstractclass;p1, Templatemethod (); // Call virtual functions in Concretetclass New concreteclass;p2->templatemethod ();
The results of the output are as follows:
Operation1 from AbstractClass! Operation2 from AbstractClass! Operation1 from Concreteclass! Operation2 from Concreteclass!
This result, at first glance, is not immediately problematic because the derived class overrides two virtual functions, which are also private member functions of the derived class itself, and it is no problem to invoke the virtual function in its own class.
5.2 Virtual functions are not overridden
The following changes the program, the derived class Concreteclass not rewrite two virtual functions, but simply inherit from the base class AbstractClass, as follows:
class Public AbstractClass {};
Execute program, output result:
Operation1 from AbstractClass! Operation2 from AbstractClass! Operation1 from AbstractClass! Operation2 from AbstractClass!
This time the question arises: how can the derived class Concreteclass actually access the private virtual function of the base class AbstractClass? It's a private type !
In fact, this is an illusion, not the derived class directly calls the private virtual function of the base class, but rather the non-virtual member function Concreteclass::templatemethod of the derived class ,
Because the non-virtual member function of the base class inherits from the Abstractclass::templatemethod, the private virtual function of the base class is called indirectly .
The actual "call right" is still firmly in the hands of the base class, except that the base class provides a Tempaltmethod interface (interface) that allows derived classes to invoke indirectly.
5.3 Private non-virtual functions
Modify the program again, PrimitiveOperation1 and PrimitiveOperation2 within the base class are no longer declared as virtual functions, that is, the base class withdraws the "implementation right" of the function from the derived class
class AbstractClass {public: void templatemethod (); Private : void // non-virtual void // non-virtual};
At the same time, the derived class Concreteclass, declaring its own private member functions PrimitiveOperation1 and PrimitiveOperation1, "hides" the corresponding function of the same name in the base class
class Public AbstractClass {private: void PrimitiveOperation1 (); void PrimitiveOperation2 ();};
Execute program output Result:
Operation1 from AbstractClass! Operation2 from AbstractClass! Operation1 from AbstractClass! Operation2 from AbstractClass!
The result of the output is the same as 5.2, the derived class calls Concreteclass::templatemethod, and Concreteclass::templatemethod inherits from AbstractClass:: Templatemethod,
Therefore, in fact, it is still a non-virtual member function within the base class, calling the private member function within the base class
5.4 Pure virtual function
Reiterate the sentence in 5.1: When a virtual function is called through a pointer or reference, the specific call to the base class or the virtual function in the derived class depends on the private member function in the base class of the class object that is dynamically bound to the pointer or reference
As you can see, virtual functions involve dynamic binding, and it's not much of a matter of whether it's public, private, or protected.
In practice, since the template method pattern is used, it is necessary to rewrite PrimitiveOperation1 and PrimitiveOperation2 in the derived class Concreteclass.
to ensure that both functions are bound to be overridden by derived classes, you can declare them as pure virtual functions, that is, add "= 0" at the very end of the function, as follows:
class AbstractClass {public: void templatemethod (); Private : Virtual void 0 ; Virtual void 0 ;};
At this point, because pure virtual functions are declared within the base class, all base classes AbstractClass become an abstract base class (ABSTARCT base classes)
Abstract base classes can only provide interfaces (interface), but cannot instantiate
Executing the following program is an error:
New abstractclass;p1->templatemethod ();
Summary:
1) NVI gives the derived class control over How functionality are implemented, but the base class reserves the RI Ght When the function would be called
2) Derived classes may redefine private inherited virtual functions
3) Pure Virtual functions specify inheritance of interface only
Resources:
<effective c++> Item 35
<c++ primer_5th> 15.4 Abstract Base Classes
<design patterns> Template Method
pass from reference to design mode (cont.)