First, container and inheritance
When you save an object that has an inheritance relationship in a container, the derived class is cut if it is defined to hold the base class object, and if it is defined to save the derived class object, then it becomes a problem to save the base class object (the base class object is cast to the derived class object, and the member defined in the derived class is not initialized).
The only viable option is to hold a pointer to the object in the container. However, users are required to manage objects and pointers. A common technique in C + + is the wrapper class (cover) or the handle class (handle). Use the handle class to store and manage class pointers.
The handle class generally accomplishes two things:
Manages pointers, which are similar to the functions of smart pointers.
To implement polymorphism, using dynamic binding, a pointer can either point to a base class or to a derived class.
There are two important design considerations for wrapping a handle to an inheritance hierarchy:
As with any class that holds pointers, you must determine what to do with the copy control. A handle that wraps an inheritance hierarchy usually behaves like a smart pointer or a value.
The handle class determines whether the handle interface is masked or does not mask the inheritance hierarchy, and if the inheritance hierarchy is not masked, the user must understand and use the objects in the base hierarchy (objects in theunderlying hierarchy).
Here's a simple example I wrote myself to illustrate the problem:
This example program includes a base class, a derived class, and a handle class.
Where the base class has 2 private members, the numeric m_base and the program name name. The derived class has a new private member, M_der.
Derived classes and base classes have virtual function compute. The base class compute it computes the base class member M_base squared. The compute of a derived class computes the sum of m_base squares and m_der.
The handle class has two data members, each of which is a pointer to a reference count ( this must be a pointer, the value of the copy pointer when copied , a reference count to ensure that only one of the instantiated objects has a single quote), and a pointer to the base class or its derived class.
#include <iostream>#include<string>#include<exception>using namespacestd;//base classclassBase { Public: //Basic ConstructorBase (intM_base =1,stringName ="Base"): M_base (m_base), name (name) {cout<<"Base Constructor called!"<<Endl; } //copy ConstructorBase (ConstBase &Base): Base (Base. M_base,Base. Name) {cout<<"Base copy called"<<Endl; } VirtualBase *clone ()Const { return NewBase (* This); } Const stringGetName () {returnname; } Virtual intCompute ()Const { returnM_base *m_base; } Virtual~Base () {cout<<"Base deleted"<<Endl; }protected: intm_base; stringname;};classDerived: PublicBase { Public: //Basic ConstructorDerived (intM_base,stringNameintm_der): Base (m_base, name), M_der (m_der) {cout<<"Derived Constructor called"<<Endl; } //copy ConstructorDerived (ConstDerived &derived): Derived (Derived.m_base, Derived.name, Derived.m_der) {cout<<"Derived copy called"<<Endl; } VirtualDerived *clone ()Const { return NewDerived (* This); } Virtual intCompute ()Const { //calling methods defined in the parent class returnBase::compute () +M_der; } Virtual~Derived () {cout<<"Derived deleted"<<Endl; }Private: intM_der;};classHandler { Public: //default constructorHandler (): PBase (NULL), use (New int(1)) { } //General ConstructorsHandler (ConstBase &item): PBase (Item.clone ()), use (New int(1)) { } //copy Constructor//The reference count is added 1 per copyHandler (ConstHandler &ref): PBase (ref. PBase), use (ref. Use) { ++*Use ; } //Overloaded assignment operatorHandler &operator=(ConstHandler &Right ) { ++*(Right.use); Decrese_use (); PBase=right.pbase; use=Right.use; return* This; } //Overloaded arrow operator ConstBase *operator()Const { if(pbase)returnpbase; Else ThrowLogic_error ("Unbound handler!"); } //Overloaded dereference operators ConstBase &operator* ()Const{ if(pbase)return*pbase; Else ThrowLogic_error ("Unbound Handler"); } voidPrint_use () {cout<< Pbase->getname () <<"Use :"<< *use <<Endl; } // Destructors~Handler () {decrese_use (); }Private: //pointers must be used here to ensure that a base instance corresponds to only one reference count int*Use ; Base*pbase; voidDecrese_use () {if(--*use = =0) {cout<< Pbase->getname () <<"is going-be deleted!"<<Endl; Deletepbase; } }};intMain () {Handler H1 (Base (2,"Base")); H1.print_use (); cout<<"Base Compute:"<< (*H1). Compute () <<Endl; Handler H2 (H1); H2.print_use (); cout<<"Base Compute:"<< (*H2). Compute () <<Endl; cout<<"-------------------------------------"<<Endl; Handler H3 (Derived (3,"derived",3)); H1=H3; H1.print_use (); cout<<"Derived Compute:"<< (*H1). Compute () <<Endl; cout<<"system Automatic Delete begin"<<Endl; return 0;}
Second, handle class
The handle class handle has 3 constructors: The default constructor, the copy constructor, and the constructor that receives the base class base object. To ensure dynamic invocation when copying concrete objects in the constructor of the base class base Object , we get the correct class instances, we define the virtual function clonein the class.
Base
Virtual Const { returnnew Base (*this);}
Derived
Virtual Const { returnnew Derived (*this);}
Iii. Results of operation
Main function Call:
intMain () {Handler H1 (Base (2,"Base")); H1.print_use (); cout<<"Base Compute:"<< (*H1). Compute () <<Endl; Handler H2 (H1); H2.print_use (); cout<<"Base Compute:"<< (*H2). Compute () <<Endl; cout<<"-------------------------------------"<<Endl; Handler H3 (Derived (3,"derived",3)); H1=H3; H1.print_use (); cout<<"Derived Compute:"<< (*H1). Compute () <<Endl; cout<<"system Automatic Delete begin"<<Endl; return 0;}
Output:
Base Constructor called! Base Constructor called! Base copy calledbase deletedbase use:1base compute:4base use:2base use:2base compute:4-------------------------------- -----Base Constructor called! Derived Constructor Calledbase Constructor called! Derived constructor calledderived copy calledderived deletedbase deletedderived use:2derived use:2derived Compute:12sys TEM Automatic Delete Beginbase is going to be deleted! Base deletedderived is going to be deleted! Derived Deletedbase deleted
The main function uses the base object to create the handler object H1, and the handler object H2 is constructed by H1, and the output lets you see that the reference count of the handler object is changed from 1 to 2. It then uses the derived object to create the handler object H3, assigns it to H1, and outputs its reference count to H1,h3, which indicates that the reference count is 2.
C + + handle class