Join Date: Aug 2007
Posts: 8643
User-Rating:
|
Hallo,
gestern bin ich über eine nette Möglichkeit gestolpert eine Klasse zu entwerfen, die jedes beliebige Objekt aufnehmen kann. Für ein aktuelles Projekt brauchte ich genau sowas...
CPP Code: #ifndef __OSHGUI_MISC_ANY_H__ #define __OSHGUI_MISC_ANY_H__ namespace OSHGui { namespace Misc { /** * Dieser Datentyp kann jeden anderen Datentyp aufnehmen. */ class Any { private: //Verhindert "ISO C++ forbids declaration of 'TypeWrapper' with no type" class AnyTypeWrapper { public: virtual ~AnyTypeWrapper() { } virtual AnyTypeWrapper* Copy() = 0; virtual void* GetObject() = 0; }; //--------------------------------------------------------------------------- template<class T> class TypeWrapper : public AnyTypeWrapper { private: T obj; public: TypeWrapper(const T &object) : obj(object) { } //--------------------------------------------------------------------------- TypeWrapper* Copy() { return new TypeWrapper<T>(obj); } //--------------------------------------------------------------------------- void* GetObject() { return &obj; } }; //--------------------------------------------------------------------------- unsigned int id; AnyTypeWrapper *wrapper; //--------------------------------------------------------------------------- static unsigned int NextID() { static unsigned int id = 0; ++id; return id; } //--------------------------------------------------------------------------- template<class T> static unsigned int TypeID() { static unsigned int id = NextID(); return id; } //--------------------------------------------------------------------------- public: /** * Erzeugt ein leeres Any-Objekt. */ Any() { id = 0; wrapper = 0; } /** * Erzeugt ein Any-Objekt, das das angegebene Objekt enthält. * * @param obj */ template<class T> Any(const T &obj) { id = TypeID<T>(); wrapper = new TypeWrapper<T>(obj); } /** * Kopierkonstruktor */ Any(const Any &any) { delete wrapper; id = any.id; wrapper = any.wrapper->Copy(); } /** * Weißt diesem Any-Objekt das angegebene zu. * * @param any * @return this */ Any& operator= (Any const& any) { if (this != &any) { delete wrapper; id = any.id; wrapper = any.wrapper->Copy(); } return *this; } /** * Dieser Operator erlaubt per if (!any) { any ist leer } zu prüfen, ob das Any-Objekt leer ist. */ operator void *() const { return (wrapper == 0 ? 0 : (void*)this); } ~Any() { delete wrapper; } /** * Castet ein Any-Objekt zu dem in ihm befindlichen Datentyp. Falls ein falscher Datentyp angegeben wird, * wird eine Exception ausgelöst. * * @return das aufgenommene Objekt */ template<class T> T CastTo() { if (TypeID<T>() == id) { return *static_cast<T*>(wrapper->GetObject()); } else { throw 1; } } }; } } #endif
verwenden kann man die Klasse so:
CPP Code: #include <iostream> #include <string> #include "Any.h" int main() { Any anything[5]; anything[0] = (int)1337; anything[1] = (char*)"char*"; anything[2] = (float)1.337f; anything[3] = std::string("std::string"); anything[4] = true; std::cout << anything[0].CastTo<int>() << std::endl << anything[1].CastTo<char*>() << std::endl << anything[2].CastTo<float>() << std::endl << anything[3].CastTo<std::string>() << std::endl << anything[4].CastTo<bool>() << std::endl; return 0; }
Verwenden kann man sowas, an allen Stellen, bei denen man nicht genau weiß, welches Objekt man speichern muss, zB ob der Benutzer ein float, string oder int eingibt. Man muss sich nur den Typ merken, in den man zurückcasten muss. Ein try catch um CastTo verhindert einen Absturz bei einem falschen Cast.
CPP Code: try { float f = anything[0].CastTo<float>(); } catch (...) { std::cout << "ist kein float!" << std::endl; }
greetz KN4CK3R
|