union
-
Hallo!
Ich möchte eine Klasse "vec3f" haben, in der drei Koordinaten (x, y, z) als floats gespeichert werden. Diese drei Koordinaten möchte ich einzeln als Membervarjiablen vec3f.x, vec3f.y, vec3f.z ansprechen können.
Gleichzeitig möchte ich diese Koordinaten direkt als Array (also Pointer) an eine Funktion übergeben können. Es ist also wichtig, dass die Variablen x, y, z genauso gespeichert werden wie es in einem Array der Fall wäre. Wie bekomme ich das hin?
So geht es offenbar nicht:union { float x, y, z; float xyz[3]; },
denn so teilen sich x, y und z alle den gleichen Speicherplatz.
Uns so funktioniert es auch nicht:class blub { public: float x, y, z; float *xyz; blub(float x, float y, float z) { this->x=x; this->y=y; this->z=z; xyz=&x; } }; int main() { blub blah(1.0f, 2.0f, 3.0f); printf("%.1f %.1f\n", blah.x, blah.xyz[0]); printf("%.1f %.1f\n", blah.y, blah.xyz[1]); printf("%.1f %.1f\n", blah.z, blah.xyz[2]); return 0; }Ausgabe ist dann hier:
1.0 1.0 2.0 1.9 3.0 0.0Gibt es da irgendeine Möglichkeit? Bitte keine so naheliegenden Vorschläge wie
void x() { return xyz[0]; } void y() { return xyz[1]; } void z() { return xyz[2]; }oder
float &operator[](unsigned i) { switch (i) { case 0: return x; case 1: return y; case 2: return z; } return whatever; }Ich möchte nämlich gern auf die Koordinaten einfach zugreifen können wie auf public Membervariablen ohne Funktionsklammern().
Und ich möchte die Elemente nicht nur durch Indizes erreichen können wie bei einem Array sondern auch, dass sie so gespeichert sind wie in einem Array, damit ich einen Array-Zeiger an eine andere Funktion übergeben kann.
Und ich will Spannung.
Und Schokolade!
Kann mir jemand helfen?Viele Grüße
Krecik
-
Es gibt keine standardkonforme Möglichkeit, dieses Layout zu erzwingen. Umgekehrt ist es dagegen sehr wohl möglich, bereits während des Compilierens zu überprüfen, ob eine Klasse
struct Foo { float x,y,z; };ein Layout äquivalent zu dem eines Arrays hat. Das dürfte für die meisten praktischen Fälle völlig ausreichen.
BOOST_STATIC_ASSERT(( sizeof( Foo ) == sizeof( float[3] ) ));
-
schau mal obs so geht:
class Vec { public: float asArray[3]; float& x; float& y; float& z; Vec() : x(asArray[0]) , y(asArray[1]) , z(asArray[2]) { } }Zur Erklärung:
hier werden 3 referenzen auf das Array erzeugt. Diese sind nur aliase und sollten zur laufzeit keinen Speischer beanspruchen!oder, was aber noch weniger schön ist:
typedef union Vec{ struct{ float x; float y; float z; }; float asArr[3] }Vec;Zugriff über
Vec a; a.x;das geht allerdings nur mit dem visual c/c++ compiler und er produziert ne warnung ("Non standard c-Estension (unnamed struct)...", oder so)
ansonsten musst du dem substruct einen namen geben und dann eben so ansprechen:
typedef union Vec{ struct{ float x; float y; float z; }asXYZ; float asArr[3] }Vec;Vec a; a.asXYZ.xIch find aber keine der Beiden lösungen gut!
Wenns eine kleine Kompakte Klasse sein soll, dann lass es so, wenns aber was größeres sein sollte, dann sollten die daten nahc außen versteckt werden:template<class T> class Vec { public: T& x() { return m_data[0] }; T& y() { return m_data[1] }; T& z() { return m_data[2] }; const T& x() { return m_data[0]; } const; const T& y() { return m_data[1]; } const; const T& z() { return m_data[2]; } const; T& operator[](int i) { return m_data[i]; }; const T& operator[](int i) { return m_data[i]; } const; /* weitere funktionen */ private: T m_data[3]; }oder etwas konventioneller per getter und setter:
template<class T> class Vec { public: const T& getX() { return m_data[0]; } const; const T& getY() { return m_data[1]; } const; const T& getZ() { return m_data[2]; } const; void setX(T i_val) { m_data[0] = i_val; } ; void setY(T i_val) { m_data[1] = i_val; } ; void setZ(T i_val) { m_data[2] = i_val; } ; T& operator[](int i) { return m_data[i]; }; const T& operator[](int i) { return m_data[i]; } const; /* weitere funktionen */ private: T m_data[3]; }Edit:
Erklärungen hizugefügt, sowie weitere Varianten und bugfixes
-
vlad_tepesch schrieb:
schau mal obs so geht:
class Vec { public: float asArray[3]; float& x; float& y; float& z; Vec() : x(asArray[0]) , y(asArray[1]) , z(asArray[2]) { } }Vielen Dank, das ist genau das, was ich brauchte. Funktioniert astrein!

Kaffee sei mit euch
Krecik
-
Gruselig. Vergiss bitte wenigstens nicht den Copy-ctor und den Zuweisungsoperator. All die anderen Probleme werden ja sowieso ignoriert, man denke nur an Sachen wie const-Korrektheit...