Polymorphic copy

So far, we have considered factory alternatives to the object constructor—either the default constructor or one of the constructors with arguments. However, a similar pattern can be applied to the copy constructor—we have an object, and we want to make a copy. 

This is a similar problem in many ways—we have an object that's accessed through the base class pointer, and we want to call its copy constructor. For the reasons we discussed earlier, not the least of which is that the compiler needs to know how much memory to allocate, the actual constructor call has to be done on the statically determined type. However, the control flow that gets us to a particular constructor call can be determined at runtime, and that, again, calls for an application of the Factory pattern.

The factory method we will use to implement polymorphic copy is somewhat similar to the Unit factory example from the previous section—the actual construction has to be done by each derived class, and the derived class knows what type of the object to construct. The base class implements the control flow that dictates that someone's copy will be constructed, and the derived class customizes the construction part:

class Base {
public:
virtual Base* clone() const = 0;
};
class Derived : public Base {
public:
Derived* clone() const { return new Derived(*this); }
};

Base* b = ... get an object somewhere ...
Base* b1 = b->clone();

Again, we are using covariant return types, and, therefore, are limited to the raw pointers. 

Let's say that we want to return unique pointers instead. Since only the raw pointers to the base and derived types are considered covariant, we have to always return the unique pointer to the base class:

class Base {
public:
virtual std::unique_ptr<Base> clone() const = 0;
};
class Derived : public Base {
public:
std::unique_ptr<Base> clone() const { // Not unique_ptr<Derived>
return std::unique_ptr<Base>(new Derived(*this));
}
};

std::unique_ptr<Base> b(...);
std::unique_ptr<Base> b1 = b->clone();

In many cases, this is not a significant limitation. Sometimes, however, it can lead to unnecessary conversions and casts. If returning a smart pointer to the exact type is important, there is another version of this pattern that we will consider next.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.77.6