Идиома виртуального конструктора является важным случаем, когда необходим конструктор закрытых или защищенных копий. Проблема возникает в C ++, где вам дается указатель на базовый класс объекта, который на самом деле унаследован от этого базового класса, и вы хотите сделать его копию. Вызов конструктора копирования не вызовет конструктор копирования наследующего класса, но фактически вызовет конструктор копирования базового класса.
Обратите внимание:
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);
Приведенный выше код выдаст результат:
"Base copy constructor"
Это явно не то поведение, которое хотел программист! Программист пытался скопировать объект типа «Производное», но вместо этого получил объект типа «База» !!
Проблема устранена с использованием вышеупомянутой идиомы. Посмотрите на приведенный выше пример, переписанный для использования этой идиомы:
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();
Приведенный выше код выдаст результат:
"Base copy constructor"
"Derived copy constructor"
Другими словами, объект, который был построен в желаемом типе «Производный», а не в типе «База»!
Как вы можете видеть, в типе Derived конструктор копирования был преднамеренно сделан закрытым, потому что было бы плохо спроектировать API, чтобы дать программистам возможность случайно попытаться вызвать конструктор копирования вручную, а не использовать предоставленный умный интерфейс. по клону (). Иными словами, доступный напрямую вызываемый общедоступный конструктор копирования может привести к тому, что программисты допустят ошибку, упомянутую в части 1. В этом случае в соответствии с передовой практикой конструктор копирования будет скрыт от просмотра и доступен только косвенно с помощью метода "clone ( )».