OldSchoolHack

Register / Login English

[C++] Any


icon [C++] Any #1

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
icon #2

Join Date: Nov 2010

Posts: 181

Schöne klasse

__________________

Ich liebe Kekse

Only registered and activated users can see links.

CHEAT CODING IS NOT A CRIME
icon #3

Join Date: Aug 2008

Posts: 2594

User-Rating:

17 positive
5 negative
Cool, gibts aber so was nicht schon?
icon #4

Join Date: Aug 2007

Posts: 8643

User-Rating:

199 positive
33 negative
nicht im Standard, nur über irgendwelche externen Libs wie Boost zB und wenn du "auto" meinst, dann is das auch nicht das richtige

greetz KN4CK3R

__________________

Hallo
icon #5

Join Date: Aug 2008

Posts: 2594

User-Rating:

17 positive
5 negative
Quote from KN4CK3R
nicht im Standard, nur über irgendwelche externen Libs wie Boost zB und wenn du "auto" meinst, dann is das auch nicht das richtige

greetz KN4CK3R
Hmmm und für was hast du es gebraucht?
icon #6

Join Date: Aug 2007

Posts: 8643

User-Rating:

199 positive
33 negative
um im GUI bei einzelnen Steuerlementen ein Tag vergeben zu können wie bei C# zB. Da ist das vom Typ Object aber das gibts in C++ nur durch so gefrickel.

greetz KN4CK3R

__________________

Hallo
icon #7

Join Date: Aug 2008

Posts: 2594

User-Rating:

17 positive
5 negative
Quote from KN4CK3R
um im GUI bei einzelnen Steuerlementen ein Tag vergeben zu können wie bei C# zB. Da ist das vom Typ Object aber das gibts in C++ nur durch so gefrickel.

greetz KN4CK3R
Aso, na mal sehen, wie es dann am ende aussieht.^^