Das virtuelle Klonmuster wird häufig verwendet, um Probleme wie diese zu lösen. Klassische Lösungen neigen dazu, für die Methode clone()
co-variante Rückgabetypen zu verwenden. Andere Lösung injizieren eine Factory-Typ-Klasse (mit CRTP) zwischen der Basis und den abgeleiteten Klassen. Es gibt sogar Lösungen, die diese Funktionalität nur mit Makros implementieren. Siehe die C++ FAQ, C++ idioms und eine blog on this. Jede dieser Lösungen ist praktikabel, und die geeignetste hängt vom Kontext ab, in dem sie verwendet werden und verwendet werden sollen.
Ein klassischer Ansatz, mit covariant return types und gekoppelt mit moderneren RAII-Techniken (shared_ptr
et al.) Bietet eine sehr flexible und sichere Kombination. Einer der Vorteile des kovarianten Rückgabetyps besteht darin, dass Sie in der Lage sind, einen Klon auf derselben Ebene in der Hierarchie wie das Argument zu erhalten (d. H. Die Rückgabe erfolgt nicht immer zur Basisklasse).
Die Lösung erfordert Zugriff auf shared_ptr
und/oder unique_ptr
. Falls Booster mit Ihrem Compiler nicht verfügbar ist, bietet Boost Alternativen für diese. Die clone_shared
und clone_unique
sind den entsprechenden make_shared
und make_unique
Dienstprogrammen der Standardbibliothek nachgebildet. Sie enthalten explizite Typprüfungen für die Klassenhierarchie der Argumente und Zieltypen.
#include <type_traits>
#include <utility>
#include <memory>
class CBaseClass {
public:
virtual CBaseClass * clone() const {
return new CBaseClass(*this);
}
};
class CDerivedClass : public CBaseClass {
public:
virtual CDerivedClass * clone() const {
return new CDerivedClass(*this);
}
};
class CMoreDerivedClass : public CDerivedClass {
public:
virtual CMoreDerivedClass * clone() const {
return new CMoreDerivedClass(*this);
}
};
class CAnotherDerivedClass : public CBaseClass {
public:
virtual CAnotherDerivedClass * clone() const {
return new CAnotherDerivedClass(*this);
}
};
// Clone factories
template <typename Class, typename T>
std::unique_ptr<Class> clone_unique(T&& source)
{
static_assert(std::is_base_of<Class, typename std::decay<decltype(*source)>::type>::value,
"can only clone for pointers to the target type (or base thereof)");
return std::unique_ptr<Class>(source->clone());
}
template <typename Class, typename T>
std::shared_ptr<Class> clone_shared(T&& source)
{
static_assert(std::is_base_of<Class, typename std::decay<decltype(*source)>::type>::value,
"can only clone for pointers to the target type (or base thereof)");
return std::shared_ptr<Class>(source->clone());
}
int main()
{
std::unique_ptr<CDerivedClass> mdc(new CMoreDerivedClass()); // = std::make_unique<CMoreDerivedClass>();
std::shared_ptr<CDerivedClass> cloned1 = clone_shared<CDerivedClass>(mdc);
std::unique_ptr<CBaseClass> cloned2 = clone_unique<CBaseClass>(mdc);
const std::unique_ptr<CBaseClass> cloned3 = clone_unique<CBaseClass>(mdc);
// these all generate compiler errors
//std::unique_ptr<CAnotherDerivedClass> cloned4 = clone_unique<CAnotherDerivedClass>(mdc);
//std::unique_ptr<CDerivedClass> cloned5 = clone_unique<CBaseClass>(mdc);
//auto cloned6 = clone_unique<CMoreDerivedClass>(mdc);
}
Ich habe hinzugefügt, eine CMoreDerivedClass
und CAnotherDerivedClass
die Hierarchie ein wenig besser zu zeigen Typen Kontrollen usw.
Sample code
Wie über eine virtuelle Memberfunktion 'clone' zu erweitern? –
'Clone' sollte eine virtuelle Member-Methode sein, die von jeder Klasse Ihrer Hierarchie implementiert wird, einschließlich' CDerivedClass' – quantdev
mögliches Duplikat von [Wie klonst du Objekte in C++? Oder gibt es eine andere Lösung?] (Http://stackoverflow.com/questions/12902751/how-to-clone-object-in-c-or-is-there-another-solution) – quantdev