 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Markus Moll Guest
|
Posted: Tue Feb 21, 2006 6:06 pm Post subject: clone()-Funktionalität hinzufügen |
|
|
Hallo
Ich habe hier eine bestehende (halbwegs größere) Klassenhierarchie,
weitgehend (durchgehend?) single-inheritance. Es gibt eine gemeinsame
Basisklasse, nennen wir sie Base.
Nun überlege ich, wie man dort einfach clone()-Funktionalität (virtuelle
Funktion, die eine Kopie des most-derived objects zurückgibt) hinzufügen
kann. Das ganze soll möglichst wenig intrusiv sein, das Hinzufügen einer
virtuellen Funktion ist mir schon zu hart (und zu fragil: was passiert,
wenn man die mal vergißt?).
Jetzt kam mein krankes Hirn auf folgendes:
- Ich bastele eine CloneFactory. Diese soll dynamisch registrierte Typen
kopieren können.
- Dies geschieht über eine map von type_info-wrappern auf Kopierobjekte
(Memory overhead im Vergleich zu clone()-Funktionen, aber na gut )
- Registrierung geschieht über templatifizierte Basisklasse
Damit braucht man "nur" jede Klasse von einer weiteren erben lassen.
Tut man das nicht, oder vererbt man von der falschen, so kann man solche
Objekte nicht clonen.
Das Minimalbeispiel wird leider schon recht lange... hier ist es trotzdem:
// -----------------------------------------------------------
#include <boost/shared_ptr.hpp>
#include <map>
#include <typeinfo>
#include <iostream>
// wraps std::type_info, needed to map from type_info
struct type_info_wrapper
{
const std::type_info *ti;
type_info_wrapper(const std::type_info& ti) : ti(&ti) {}
bool operator< (const type_info_wrapper& t2) const
{
return ti->before(*t2.ti);
}
};
struct Base
{
virtual ~Base() {}
boost::shared_ptr<Base> clone() const;
};
struct bad_clone {}; // exception
struct clone_base
{
virtual ~clone_base() {}
virtual boost::shared_ptr<Base> clone(const Base&) const = 0;
};
class CloneFactory
{
std::map<type_info_wrapper, boost::shared_ptr<clone_base> >
clone_map;
CloneFactory() {}
static CloneFactory *instance;
public:
boost::shared_ptr<Base> clone(const Base& b)
{
boost::shared_ptr<clone_base> c clone_map[typeid(b)];
if(!c) throw bad_clone();
return c->clone(b);
}
void register_cloner(const std::type_info& ti,
boost::shared_ptr<clone_base> cb)
{
clone_map[ti] = cb;
}
static CloneFactory* the()
{
if(!instance) instance = new CloneFactory();
return instance;
}
};
CloneFactory* CloneFactory::instance = 0;
boost::shared_ptr<Base> Base::clone() const
{
return CloneFactory::the()->clone(*this);
}
template<typename T>
struct cloner : virtual public clone_base
{
virtual boost::shared_ptr<Base> clone(const Base &obj) const
{
if(typeid(T) != typeid(obj)) throw bad_clone();
return boost::shared_ptr<Base>( new T( *static_cast<const
T*>(dynamic_cast<const void*>(&obj) ) ) );
}
};
template<typename T>
class clone_registrant
{
struct aux
{
aux()
{
CloneFactory::the()->register_cloner(typeid(T),
boost::shared_ptr<clone_base>(new cloner<T>()));
}
};
public:
clone_registrant()
{
static aux doitonce;
}
};
// User code (derived classes)
struct Der1 : public Base, private clone_registrant<Der1>
{
};
struct Der2 : public Der1, private clone_registrant<Der2>
{
};
int main()
{
boost::shared_ptr<Base> p1( new Der1() );
boost::shared_ptr<Base> p2( p1->clone() );
std::cerr << typeid(*p2).name() << "\n";
}
// ------------------------------------------------------------
Dazu: ist das übermäßig kompliziert? (es erscheint mir so)
Geht der dynamic_cast oben gut? (So wie ich das lese schon)
(Nomenklatur ist merkwürdig, darum soll's mal nicht gehen)
Gruß
Markus
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de |
|
| Back to top |
|
 |
Torsten Robitzki Guest
|
Posted: Tue Feb 21, 2006 8:06 pm Post subject: Re: clone()-Funktionalität hinzufügen |
|
|
Markus Moll wrote:
Hallo Markus,
| Quote: | Ich habe hier eine bestehende (halbwegs größere) Klassenhierarchie,
weitgehend (durchgehend?) single-inheritance. Es gibt eine gemeinsame
Basisklasse, nennen wir sie Base.
Nun überlege ich, wie man dort einfach clone()-Funktionalität (virtuelle
Funktion, die eine Kopie des most-derived objects zurückgibt) hinzufügen
kann. Das ganze soll möglichst wenig intrusiv sein, das Hinzufügen einer
virtuellen Funktion ist mir schon zu hart (und zu fragil: was passiert,
wenn man die mal vergißt?).
|
das eigentliche Problem ist also, zu ermitteln, ob der dynamische und
statische Typ gleich sind (welches sich nur zu Compilezeit ermitteln
läßt) bzw. sicher zu stellen, das die gegebene Klasse die äußerst
ableitende ist (was sich in C++ nicht feststellen läßt).
| Quote: | Jetzt kam mein krankes Hirn auf folgendes:
- Ich bastele eine CloneFactory. Diese soll dynamisch registrierte Typen
kopieren können.
- Dies geschieht über eine map von type_info-wrappern auf Kopierobjekte
(Memory overhead im Vergleich zu clone()-Funktionen, aber na gut )
- Registrierung geschieht über templatifizierte Basisklasse
Damit braucht man "nur" jede Klasse von einer weiteren erben lassen.
Tut man das nicht, oder vererbt man von der falschen, so kann man solche
Objekte nicht clonen.
Das Minimalbeispiel wird leider schon recht lange... hier ist es trotzdem:
snip
Dazu: ist das übermäßig kompliziert? (es erscheint mir so)
Geht der dynamic_cast oben gut? (So wie ich das lese schon)
(Nomenklatur ist merkwürdig, darum soll's mal nicht gehen)
|
Ich hätte mir evtl. clone_base{} gespart und einen einfachen
Funktionsprototypen verwendet und aus CloneFactory{} evtl. einfach eine
statische map<> in Base{} gemacht. Die Idee finde ich gut, und über den
Overhead würde ich mir keine Gedanken machen, da die meisten
Implementierungen von new() die paar Tests überwiegen sollten.
Du verschiebst allerdings den Zeitpunkt, zu dem Du (Teil-) Fehler in
Deiner Software finden kannst von der Compile-zeit zur Laufzeit. Das muß
einem halt klar sein, wenn man Deine Lösung verwendet.
mfg Torsten
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|