C ++ proxy design (1)

Source: Internet
Author: User

Purpose: Make the designed container have the ability to contain objects of different types and related to each other.

Generally, a container can only contain one type of object, so it is difficult to store the object itself in the container. The pointer to the object is stored. Although inheritance is allowed to handle different types of problems (polymorphism), it also increases the extra burden of memory allocation. Therefore, we can solve this problem by defining an object named proxy. The agent runs basically the same as the object it represents, but allows the entire hierarchy to be compressed into an object type.

Assume there is a class hierarchy that represents different types of transport:

class Vehicle{public: virtual double weight() const = 0; virtual void start() = 0; //...};class RoadVehicle:public Vehicle{/*...*/};class AutoVehicle:public Vehicle{/*...*/};class Aircraft:public Vehicle{/*...*/};class Helicopter:public Vehicle{/*...*/};

It can be seen that Vehicle is an abstract base class with two pure virtual functions representing some common attributes. Next, let's see why the following sentence cannot achieve the expected results:

Vehicle parking_lot [1000];

On the surface, Vehicle is an abstract base class. Therefore, only classes derived from the Vehicle class can be instantiated. the Vehicle class itself does not have objects and naturally does not have an array of objects.

However, if we remove all pure virtual functions in the Vehicle class so that their objects exist, what will happen? See the following statement:

Automobile x = /*...*/;

Parking_lot [num_vehicles ++] = x;

The element that assigns x to parking_lot converts x into a Vehicle object and loses all the members not in the Vehicle class. The value assignment statement also copies the cropped object to the parking_lot array. In this way, we can only say that parking_lot is a set of Vehicle, rather than a set of all objects inherited from Vehicle.

Classic Solution ------ provides an indirect Layer

The earliest appropriate form of indirect layer is to store pointers, rather than the object itself:

Vehicle * parking_lot [1000];

Then

Automobile x = /*...*/;

Parking_lot [num_vehicles ++] = & x;

This method solves urgent problems, but it also brings about two new problems.

① We store the pointer to x in parking_lot. In the above example, it is a local variable. In this way, once the variable x is gone, parking_lot does not know what to point.

We can make this work ing. The value in parking_lot is not a pointer to the original object, but a pointer to their copies. When we release parking_lot, all objects pointed to in it are also released.

② Although the above modification does not need to store pointers to local objects, it also brings about the burden of dynamic memory management. In addition, this method works only when we know the static type of the object to be put in parking_lot. What will happen if I don't know? See the following:

If (p! = Q)

{

Delete parking_lot [p];

Parking_lot [p] = parking_lot [q];

}

In this case, parking_lot [p] And parking_lot [q] point to the same object, which is not what we want. The following line does not work:

If (p! = Q)

{

Delete parking_lot [p];

Parking_lot [p] = new Vehicle (* parking_lot [q]);

}

In this way, we return to the previous problem: there is no Vehicle type object, even if there is, it is not what we want (it is a cropped object ).

How to copy objects with unknown types during compilation ------- virtual copy Function

In the Vehicle class above, we add a suitable pure virtual function:

Class Vehicle
{
Public:
Virtual double weight () const = 0;
Virtual void start () = 0;

Virtual Vehicle * copy () const = 0;
//...
};

Next, add a new member function copy to each class derived from Vehicle. The guiding ideology is that if vp points to an object that inherits an uncertain class from Vehicle, vp-> copy () will get a pointer pointing to a new copy of the object. For example, if Truck inherits from (indirectly or directly) the Vehicle class, its copy function is similar:

Vehicle * Truck: copy () const

{

Return new Truck (* this );

}

After processing an object, clear the object. To do this, make sure that the Vehicle class has a virtual destructor:

Class Vehicle
{
Public:
Virtual double weight () const = 0;
Virtual void start () = 0;

Virtual Vehicle * copy () const = 0;

Virtual ~ Vehicle (){}
//...
};
With the above analysis, we will define the proxy class below:

class VehicleSurrogate{public:VehicleSurrogate();VehicleSurrogate(const Vehicle&);~VehicleSurrogate();VehicleSurrogate(const VehicleSurrogate&);VehicleSurrogate& operator = (const VehicleSurrogate&);private:Vehicle* vp;};

The above proxy class has a const Vehicle & as the parameter to create a proxy for any objects that inherit from the Vehicle class (polymorphism, because here is the reference parameter ). At the same time, the proxy class also has a default constructor, so we can create an array of VehicleSurrogate objects.

However, the default constructor also brings us a problem: If Vehicle is an abstract base class, how should we specify the default operation of VehicleSurrogate? What is the object type it points? It is impossible to be a Vehicle, because there is no Vehicle object at all. To get a better method, we need to introduce the concept of a null proxy with a behavior similar to a zero pointer. A proxy can be created, destroyed, or copied, but other operations are considered as errors.

The following describes the definitions of various functions:

VehicleSurrogate: VehicleSurrogate (): vp (0) {} VehicleSurrogate: VehicleSurrogate (const Vehicle & v): vp (v. copy () {} // required for non-Zero Detection Room, empty proxy VehicleSurrogate ::~ VehicleSurrogate () {delete vp; // in the C ++ standard, it is no problem to use delete as a null pointer} VehicleSurrogate: VehicleSurrogate (const VehicleSurrogate & v): vp (v. vp? V. vp-> copy (): 0) {} VehicleSurrogate & VehicleSurrogate: operator = (const VehicleSurrogate & v) {if (this! = & V) // checks the value assignment operator to ensure that the proxy is not assigned to itself {delete vp; vp = (v. vp? V. vp-> copy (): 0); // non-zero check is required, empty proxy} return * this ;}

Below we can easily define our array:

VehicleSurrogate parking_lot [1000];

Automobile x;

Parking_lot [num_vehicles ++] = x;

The last statement is equivalent

Parking_lot [num_vehicles ++] = VehicleSurrogate (x );

This statement creates a copy of 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 will also be cleared.

Zookeeper

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.