C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

clone()-Funktionalität hinzufügen

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German)
View previous topic :: View next topic  
Author Message
Markus Moll
Guest





PostPosted: Tue Feb 21, 2006 6:06 pm    Post subject: clone()-Funktionalität hinzufügen Reply with quote



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 Sad )
- 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





PostPosted: Tue Feb 21, 2006 8:06 pm    Post subject: Re: clone()-Funktionalität hinzufügen Reply with quote



Markus Moll wrote:
Quote:
Hallo

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 Sad )
- 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
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.