Template Klasse CMatrix (Typ(4/4))
-
Der größte Witz an der Sache ist das Template ansich. Hättest Du wirklich eine eigene Matrix geschrieben wären einige Dinge ja noch sinnvoll, da D3DMatrix meines Wissens aber nur floats unterstützt ...
Bist Du evtl. ein wenig masochistisch veranlagt?
-
LOL, war wohl ein Griff ins KLo. ^^
Nagut, dann enttemplatesiere ich die mal...
Möge man es als Übung betrachten.
-
Seraph schrieb:
Bist Du evtl. ein wenig masochistisch veranlagt?
LOL
Also ich könnte das Template für meine OpenGL programmierung benutzen weil ich lieber double als float benutze und da könnte man dann seinen Dateityp angeben (z.B. nen eigenen für Abwärtskompatibilität). aber 1. Fehlen da haufenweise funktionen und 2. ist das Konzept irgendwie naja...
-
Nagut, die paar Funktionen, die noch nötig sind, kann ich theoretisch dazu machen, ich habe sie gestern ja auch nur auf den letzten Drücker fertigbekommen, das wird alles folgen.
Aber wie gesagt, jetzt wird sie zu reinem <float>
Und dann bekommt sie noch ein paar Funktionen hier und da und dann ist die Engine v0,39 fertigMfG MAV
-
das static wird nicht nur bei Multithreaded eklig!
nehmen wir mal A,B als Matrizen und v,w als Vektoren:
vector<float> c = A*v+B*w;
wir mit ziemlicher Sicherheit schief gehen:
Es wird A*v ausgewertet, was wir aber kriegen ist nur die Referenz auf das statische Objekt, dann wird B*w ausgewertet und das statische Objekt wird wieder geändert... das heißt im Endeffekt kriegen 2*B*w raus. Und das schönste ist: Der Compiler kann auch andere Reihenfolgen machen, das heißt: Jeder Compiler darf was anderes rauskriegen und sogar der selbe Compiler darf verschiedene Ergebnisse an verschiedenen Stellen für den gleichen Ausdruck liefern...Warum schreibst Du eigentlich eine Matrix, wenn nichtmal Dein vector richtig gefixt ist? Laut Source im ZFX dreht Dein Vector mit dem unären operator- immer noch den Vektor um, anstatt nur eine Kopie zu drehen.
-
OK, static verwende ich nicht merh...
template<class T> CVector<T> CVector<T>::operator-() { CVector<T> temp(*this); temp.m_x = -m_x; temp.m_y = -m_y; temp.m_z = -m_z; return temp; }
Ist das nicht korrekt?
MfF MAV
-
Doch, das stimmt, ist aber nicht sonderlich schnell, warum konstruieren+zuweisen, wenn Du schon einen passenden Konstruktor hast?
template<class T> const CVector<T> CVector<T>::operator-()
{
return CVector<T>(-m_x, -m_y, -m_z);
}tut es doch auch.
Rückgabewert sollte außerdem konnst sein, da man dem Wert sonst was zuweisen kann und das ist nicht sinnvoll!Achja, Dein operator* der Matrix ist mal wieder nicht mit Hilfe des operator*= implementiert. Tippst Du gerne viel?
MfG Jester
-
Dem Ersteren sitmme ich zu.
Aber wenn ich einfach nur CMatrix zurückgebe, ist das doch dann eine Kopie, die man auch verändern darf, oder?
Und beim Letzteren... ich bin mir einfach nicht sicher, ob man das so machen kann i.d.F.
MfG MAV
-
Naja,
-v=blablabla ist halt nicht sinnig, daher sollte es konst sein.
Man sollte sich beim Entwurf immer int als Vorbild nehmen, ist etwas bei ints erlaubt, dann sollte man es auch erlauben, erlauben es die ints nicht, dann sollte man es auch nicht machen, oder kurz: "do as the ints do"a+b=c ist mit ints verboten, also sollte eine selbst geschriebene klasse das auch nicht zulassen. Das macht die Benutzung Deiner Klassen intuitiver.
und die operatoren mit Hilfe anderer zu implementieren ist fast immer möglich!
Erst Kopie anlegen, dann mit dieser die Operation ausführen, Kopie zurückgeben:
template<class T> const CMatrix<T> CMatrix<T>::operator*(const CMatrix<T>& m) const { CMatrix<T> temp(*this); // Copy-Konstruktor temp*=m; // operator*=, der macht keine Kopien und so return temp; }
Der Vorteil ist: wenn Du operator*= einmal richtig hast, dann haste auch den operator* gleich mit richtig und denken mußte auch nix mehr dabei.
MfG Jester
-
Ja, ich dachte aber folgendes (das mit const ist jetzt glaube ich ich klar; danke :))
CMatrix& CMatrix::operator*=(const CMatrix& m) { CMatrix temp; for(unsigned short i = 0; i < 4; ++i) for(unsigned short j = 0; j < 4; ++j) for(unsigned short k = 0; k < 4; ++k) temp.m_data[j][i] += m_data[k][i] * m.m_data[j][k]; return (*this = temp); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ const CMatrix CMatrix::operator*(const CMatrix& m) const { CMatrix temp; for(unsigned short i = 0; i < 4; ++i) for(unsigned short j = 0; j < 4; ++j) for(unsigned short k = 0; k < 4; ++k) temp.m_data[j][i] += m_data[k][i] * m.m_data[j][k]; return temp; }
Wennn ich jetzt in * den Operator *= verwende, dann legt er insgesamt 2 temporäre Variablen an, nämlich in * und in *=
Diese Variante müsste daher IMHO schneller sein, oder?
MfG MAV
-
Okay, das sehe ich ein. Dennoch solltest Du den Code nicht zweimal schreiben!
Wie wäre es mit einem privaten Membervoid Multiply(const CVector<T> & A, const CVector<T> & B, CVector<T> & Erg) { // Code berechnet A*B und schreib in Erg rein. } operator* { // temp anlegen Multiply(A,B, temp); return temp; } operator *= { // temp anlegen Multilply(*this, A, temp); *this = temp; }
Bei Multiply muß man halt aufpassen, daß temp wirklich von A und B verschieden ist, sonst knallt es, aber die Funktion ist ja privat, daher ist es nicht so shlimm.
-
Oder halt in *= schreiben "*this = *this * matrix2;".
-
Jo, aber das ist wohl eher unüblich. Normalerweise macht man eher * mit *=.
Andersrum hab ich's bis jetzt nur bei Mis2Com's CVector gesehen...
-
Jester schrieb:
Normalerweise macht man eher * mit *=.
Weil man *= oft in-place machen kann. Das klappt bei der Matrix leider nicht ...
-
in der multiply() sache darf man nur nicht vergessen zu testen ob
A||B == Erg sind an sonsten gibt es ein Drama.
-
Ach ich lass es jetzt einfach mal so, dieser kleine Schönheitsfehler ist IMHO zu verkraften
Danke für euer aller Hilfe.
Das war eben meine zweite Templateklasse, vorher hab ich die Dinger netmal angerührt.
Jetzt bin ich besser informiert, thx.
MfG MAV