The "virtual constructor idiom" is an important case where a private or protected copy constructor is needed. A problem arises in C++ where you are given the pointer to a base class, of an object that is actually inherited from this base class, and you want to make a copy of it. Calling the copy constructor would not call the copy constructor of the inheriting class, but actually call the copy constructor of the base class.
Observe:
class Base {
public:
Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};
class Derived : public Base {
public:
Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}
Base * obj = new Derived;
Base * obj2 = new Derived(*obj);
The code above would produce the output:
"Base copy constructor"
This is clearly not the behaviour the programmer wanted! The programmer was attempting to copy an object of type "Derived" but instead got back an object of type "Base"!!
The issue is rectified by using the aforementioned idiom. Observe the example written above, re-written to use this idiom:
class Base {
public:
virtual Base * clone () const = 0; //this will need to be implemented by derived class
protected:
Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};
class Derived : public Base {
public:
virtual Base * clone () const {
//call private copy constructor of class "Derived"
return static_cast<Base *>( new Derived(*this) );
}
//private copy constructor:
private:
Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}
Base * obj = new Derived;
Base * obj2 = obj->clone();
The code above would produce the output:
"Base copy constructor"
"Derived copy constructor"
In other words, the object that was constructed in of desired type "Derived", and not of the type "Base"!
As you can see, in the Derived type, the copy constructor was intentionally made private, because it would be bad API design to give programmers to ability to accidentally try to call the copy constructor manually, rather than using the clever interface provided by clone(). Put another way, a directly callable public copy constructor available could cause programmers to make the mistake mentioned in part 1. In this case, best practise would have the copy constructor be hidden from view, and only indirectly accessible by using the method "clone()".