As every C + + programmer should know, the runtime polymorphic behavior occurs only when a program calls a virtual function by a pointer to a base class object or a reference to a base class object.
The meaning of this model may not be obvious. In particular, the creation and replication of objects is not run-time polymorphic, which seriously affects the design of the class. Therefore, a container (whether it is a built-in container like an array or struct or a user-defined container Class) can get only the element values that are known at compile-time types. If there is an inheritance relationship between a series of classes, when we need to create, copy, and store objects, and the exact type of those objects is only known to the runtime, then this compile-time check can cause some trouble.
In general, the solution to this problem is to add an indirect layer. The traditional C model may suggest using pointers to implement this indirect layer. Doing so has a negative impact on users who need to use these classes, so they have to be involved in memory management, which is a tedious and highly error-prone task. C + + employs a more natural approach, which is to define a class to provide and hide the indirection layer.
This class is often called a handle class. The handle class takes the simplest form of bundling an object of a single type with an object of any type that has a particular inheritance relationship with it. So, the handle allows us to ignore the exact type of object being processed, while also avoiding the problem of memory management by pointers. A common use of handle classes is to optimize memory management by avoiding unnecessary replication.
The first introduction of proxies (surrogate) is the simplest of the handle classes.
Question: Suppose there is a class-derived hierarchy that represents a different kind of vehicle:
classVehicle { Public: Virtual DoubleWeight ()Const=0; Virtual voidStart () =0; //...};classRoadvehicle: Publicvehicle{...};classAutovehicle: Publicroadvehicle {...};classAircraft: PublicVehicle {...};classHelicopter: PublicAircraft {...};
All vehicle have some common properties for member declarations in the class vehicle. However, some vehicle have properties that other vehicle do not have.
Let's say we're going to follow a series of different kinds of vehicle. In practice, we may use some kind of container class;
First we want a way to replicate objects that are unknown at compile time. We know that the way to handle objects of unknown types in C + + is to use virtual functions.
Since we want to be able to replicate any type of vehicle, all should add an appropriate pure virtual function in the vehicle class:
classvehicle{ Public: Virtual DoubleWeight ()Const=0; Virtual voidStart () =0; Virtualvehicle* copy ()Const=0; Virtual~Vehicle () {}; //...};//Next, add a new member function copy to each class that derives from vehicle. If the VP points to an object of an indeterminate class that inherits from vehicle, Vp->copy () obtains a pointer to a new copy of the object. If truck inherit vehicle,Vehicle* Truck::copy ()Const{ return NewTruck (* This); }
To avoid the display of memory allocations, you can maintain the properties that the class vehicle at run time.
We begin to define the proxy classes, each of which represents an object that inherits from the vehicle class. Vehicle As long as the agent is associated with this object, the object must exist.
classVehiclesurrogate { Public: Vehiclesurrogate (); Vehiclesurrogate (ConstVehicle &); Vehiclesurrogate (ConstVehiclesurrogate &); Vehiclesurrogate&operator=(ConstVehiclesurrogate &); ~vehiclesurrogate (); Operations from the class vehicle
Double weight () const;
void Start ();
.... Private: Vehicle*VP;};/*the proxy class above has a constructor that takes the const Vehicle & as a parameter to create a proxy for any object that inherits from the Vehicle class. At the same time, the proxy class has a default constructor, so we can create an array of Vehiclesurrogate objects. However, the default constructor also gives us a problem: If vehicle is an abstract base class, how should we specify it? We introduce an empty proxy that behaves like a 0 pointer, capable of creating, destroying, and replicating such proxies, but doing something else is an error. */vehiclesurrogate::vehiclesurrogate (): VP (0) {}vehiclesurrogate::vehiclesurrogate (ConstVehicle &v): VP (V.copy ()) {}vehiclesurrogate::vehiclesurrogate (ConstVehiclesurrogate &vs): VP (VS.VP? Vs.vp->copy ():0) {}vehiclesurrogate:: vehiclesurrogate&operator=(ConstVehiclesurrogate &vs) { if(&vs! = This) { DeleteVP; VP= (VS.VP? V.vp->copy ():0); } return* This;}
Note that these functions are not virtual: the objects we use here are objects of class vehiclesurrogate, and there are no objects that inherit from the class. Of course, the function itself can invoke the virtual function in the corresponding vehicle object. They should also check to make sure VP is not zero:
DoubleVehiclesurrogate::weight ()Const{ if(VP = =0) Throw "empty vehiclesurrogate.weight ()"; returnVp->weight ();}voidVehiclesurrogate::start () {if(VP = =0) Throw "empty Vehiclesurrogate.start ()"; VP-start ();}
Once the above work is done, we can easily define our array.
Vehiclesurrogate parking_lot[1000];
Automobile x;
parking_lot[num_vehicles++] = x;
The last statement is equivalent to
parking_lot[num_vehicles++] = vehiclesurrogate (x);
This statement creates a copy of the object x, binds the Vehiclesurrogate object to the copy, and assigns the object to an element of Parking_lot. When the Parking_lot array is finally destroyed, all these copies are also cleared.
Summary: Sharing inheritance and containers forces us to handle two problems: controlling memory allocations and putting different types of objects into the same container. Using the basic C + + technology and using classes to represent concepts, we can take both of these issues into consideration. To do these things, we propose a class called the proxy class, where each object of this class represents another object, which can be an object of any class in a complete inheritance hierarchy. This solves our problem by means of proxy objects in the container, not the object itself.
C + + Meditation--proxy class