OldSchoolHack

Register / Login English

[C++] Any

icon Thread: [C++] Any

Join Date: Aug 2007

Posts: 8643

User-Rating:

199 positive
33 negative
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