Question: How to design a container that can contain objects of different types but related to each other?
Problem description: how to copy unknown objects of the compilation type?
Solution 1: Use the container to store pointers to objects and process different types of objects through inheritance.
This solution has serious problems:
Problem 1: the pointer in the container cannot point to a local variable, for example:
Vehicle * parking_lot [1000];
Automobile x = /*..*/
Parking_lot [num_vehicles ++] = & x;
Once x does not exist, Parking_lot does not know where to point.
We can make a work ing to point the value of Parking_lot to the copy of the original object instead of directly storing the address of the original object. For example:
Parking_lot [num_vehicles ++] = new Automobile (x );
This improvement solution brings about another problem, that is, we must know the static type of x. If we want parking_lot [p] to point to the same Vehicle type and value as the object pointed to by parking_lot [q], we cannot know the static type of parking_lot [q, we cannot do this.
Solution 2 (solution 1 improvement): added a virtual replication function to copy unknown objects during compilation. The code description is as follows:
Class Vehicle
{
Public:
Virtual Vehicle * copy () const = 0;
/**/
}; // The Derived classes of Vehicle all implement the copy function.
Class Truck: public RoadVehicle
{
Public:
Vehicle * copy () const {return new Truck (* this );}
/**/
};
If we want parking_lot [p] to point to the same Vehicle type and value as the object pointed to by parking_lot [q], we can simply use the following code: parking_lot [p] = parking_lot [q]. copy ();
Solution 3 (similar to solution 2, but different implementation methods): use a proxy
Proxy class: The behavior is similar to the original class, And it potentially represents all classes inherited from the original class.
The description of VehicleSurrogate is as follows:
Class VehicleSurrogate
{
Public:
VehicleSurrogate (): vp (NULL ){};
VehicleSurrogate (const Vehicle & v): vp (v. copy ()){};
~ VehicleSurrogate (){};
VehicleSurrogate (const VehicleSurrogate & v): vp (v. vp? V. vp-> copy (): NULL) {}; // v. vp non-zero check
VehicleSurrogate & operator = (const VehicleSurrogate & v)
{
If (this! = & V) // make sure the proxy is not assigned to itself
{
Delete vp;
Vp = (v. vp? V. vp-> copy (): NULL );
}
Return * this;
};
// Operations from the Vehicle class
Void start ()
{
If (vp = 0)
Throw "empty VehicleSurrogate. start ()";
Vp-> start ();
};
Private:
Vehicle * vp;
};
After completing these tasks, we can easily define the operations we need, as shown below:
VehicleSurrogate parking_lot [1000];
Automobile x = /*..*/
Parking_lot [num_vehicles ++] = x;
// Parking_lot [num_vehicles ++] = VehicleSurrogate (x); // This statement is consistent with the previous statement.
/*...*/
Parking_lot [p] = Parking_lot [q];
Author: yucan1001