OldSchoolHack

Registrieren / Anmelden Deutsch

[C++] Any

icon Thema: [C++] Any

Anmeldungsdatum: Aug 2007

Beiträge: 8643

Benutzer-Bewertung:

199 positiv
33 negativ
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:
  1. #ifndef __OSHGUI_MISC_ANY_H__
  2. #define __OSHGUI_MISC_ANY_H__
  3.  
  4. namespace OSHGui
  5. {
  6. namespace Misc
  7. {
  8. /**
  9. * Dieser Datentyp kann jeden anderen Datentyp aufnehmen.
  10. */
  11. class Any
  12. {
  13. private:
  14. //Verhindert "ISO C++ forbids declaration of 'TypeWrapper' with no type"
  15. class AnyTypeWrapper
  16. {
  17. public:
  18. virtual ~AnyTypeWrapper() { }
  19. virtual AnyTypeWrapper* Copy() = 0;
  20. virtual void* GetObject() = 0;
  21. };
  22. //---------------------------------------------------------------------------
  23. template<class T> class TypeWrapper : public AnyTypeWrapper
  24. {
  25. private:
  26. T obj;
  27.  
  28. public:
  29. TypeWrapper(const T &object) : obj(object) { }
  30. //---------------------------------------------------------------------------
  31. TypeWrapper* Copy()
  32. {
  33. return new TypeWrapper<T>(obj);
  34. }
  35. //---------------------------------------------------------------------------
  36. void* GetObject()
  37. {
  38. return &obj;
  39. }
  40. };
  41. //---------------------------------------------------------------------------
  42. unsigned int id;
  43. AnyTypeWrapper *wrapper;
  44. //---------------------------------------------------------------------------
  45. static unsigned int NextID()
  46. {
  47. static unsigned int id = 0;
  48. ++id;
  49. return id;
  50. }
  51. //---------------------------------------------------------------------------
  52. template<class T> static unsigned int TypeID()
  53. {
  54. static unsigned int id = NextID();
  55. return id;
  56. }
  57. //---------------------------------------------------------------------------
  58.  
  59. public:
  60. /**
  61. * Erzeugt ein leeres Any-Objekt.
  62. */
  63. Any()
  64. {
  65. id = 0;
  66. wrapper = 0;
  67. }
  68. /**
  69. * Erzeugt ein Any-Objekt, das das angegebene Objekt enthält.
  70. *
  71. * @param obj
  72. */
  73. template<class T> Any(const T &obj)
  74. {
  75. id = TypeID<T>();
  76. wrapper = new TypeWrapper<T>(obj);
  77. }
  78. /**
  79. * Kopierkonstruktor
  80. */
  81. Any(const Any &any)
  82. {
  83. delete wrapper;
  84.  
  85. id = any.id;
  86. wrapper = any.wrapper->Copy();
  87. }
  88. /**
  89. * Weißt diesem Any-Objekt das angegebene zu.
  90. *
  91. * @param any
  92. * @return this
  93. */
  94. Any& operator= (Any const& any)
  95. {
  96. if (this != &any)
  97. {
  98. delete wrapper;
  99.  
  100. id = any.id;
  101. wrapper = any.wrapper->Copy();
  102. }
  103. return *this;
  104. }
  105. /**
  106. * Dieser Operator erlaubt per if (!any) { any ist leer } zu prüfen, ob das Any-Objekt leer ist.
  107. */
  108. operator void *() const
  109. {
  110. return (wrapper == 0 ? 0 : (void*)this);
  111. }
  112.  
  113. ~Any()
  114. {
  115. delete wrapper;
  116. }
  117.  
  118. /**
  119. * Castet ein Any-Objekt zu dem in ihm befindlichen Datentyp. Falls ein falscher Datentyp angegeben wird,
  120. * wird eine Exception ausgelöst.
  121. *
  122. * @return das aufgenommene Objekt
  123. */
  124. template<class T> T CastTo()
  125. {
  126. if (TypeID<T>() == id)
  127. {
  128. return *static_cast<T*>(wrapper->GetObject());
  129. }
  130. else
  131. {
  132. throw 1;
  133. }
  134. }
  135. };
  136. }
  137. }
  138.  
  139. #endif

verwenden kann man die Klasse so:
CPP Code:
  1. #include <iostream>
  2. #include <string>
  3. #include "Any.h"
  4.  
  5. int main()
  6. {
  7. Any anything[5];
  8. anything[0] = (int)1337;
  9. anything[1] = (char*)"char*";
  10. anything[2] = (float)1.337f;
  11. anything[3] = std::string("std::string");
  12. anything[4] = true;
  13.  
  14. std::cout << anything[0].CastTo<int>() << std::endl
  15. << anything[1].CastTo<char*>() << std::endl
  16. << anything[2].CastTo<float>() << std::endl
  17. << anything[3].CastTo<std::string>() << std::endl
  18. << anything[4].CastTo<bool>() << std::endl;
  19.  
  20. return 0;
  21. }

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:
  1. try
  2. {
  3. float f = anything[0].CastTo<float>();
  4. }
  5. catch (...)
  6. {
  7. std::cout << "ist kein float!" << std::endl;
  8. }

greetz KN4CK3R

__________________

Hallo