Bitte um Kritik an Implementierung einer Klasse zur Vektorrechnung



  • Hallo,

    ich habe vor ein etwas umfangreicheres Programm zu schreiben in dem ich Vektorrechnung benötige. Deshalb habe ich ersteinmal eine Klasse CVektor erstellt welche auch funktioniert. Nun ist meine Vorlesung "Grundlagen C++" schon etwas länger her und ich habe seitdem nie ernsthaft etwas damit gemacht(immer nur C auf µC). Bevor ich nun weitermache und später merke, dass das alles sehr suboptimal ist wollte ich hier mal meine Klasse vorstellen und um konstruktive Kritik bitten.

    Über jegliche Verbesserungsvorschläge würde ich mich freuen.

    Vielen Dank!

    PS: Ich habe auch noch eine gezielte Frage. Und zwar habe ich die Deklaration der Operatorübeladungen teilweise abgeschrieben. Nun ich weiß ich nicht so recht was das Ampersand da soll und ich weiß überhaupt nicht wieso es auch funktioniert wenn ich das Ampersand weglasse.(wie beispielhaft bei dem '+' Operator getan habe) 😕

    cvektor3.h

    #ifndef CVEKTOR3_H
    #define CVEKTOR3_H
    
    class CVektor3
    {
        public:
            /**Konstruktoren*/
            CVektor3();
            CVektor3(double x,double y,double z);
            ~CVektor3();
    
            /**Getters*/
            double getx();
            double gety();
            double getz();
    
            /**Setters*/
            void set(double x,double y,double z);
            void setx(double x);
            void sety(double y);
            void setz(double z);
    
            /**Vektorfunktionen*/
            double length();                 /** Betrag */
            CVektor3 unit();                 /** Einheitsvektor*/
            double dot(CVektor3 B);          /**Skalarprodukt*/
            CVektor3 kreuz(CVektor3 B);      /**Kreuzprodukt*/
            double winkel(CVektor3 B);       /**eingeschlossener winkel*/
    
            /**Operatorüberladungen*/
            CVektor3 operator+(const CVektor3 B);
            CVektor3 operator-(const CVektor3 &B);
            CVektor3 operator+(const double &N);
            CVektor3 operator-(const double &N);
            CVektor3 operator*(const double &N);
            CVektor3 operator/(const double &N);
    
        private:
            double m_x,m_y,m_z;
    };
    
    #endif //CVEKTOR3_H
    

    cvektor3.cpp

    #include <math.h>
    #include <iostream>
    
    #include "cvektor3.h"
    
    /**Konstruktoren*/
    CVektor3::CVektor3()
    :m_x(0),m_y(0),m_z(0){}
    
    CVektor3::CVektor3(double x,double y,double z)
    :m_x(x),m_y(y),m_z(z){}
    
    CVektor3::~CVektor3(){}
    
    /**Getters*/
    double CVektor3::getx()
    {return(m_x);}
    
    double CVektor3::gety()
    {return(m_y);}
    
    double CVektor3::getz()
    {return(m_z);}
    
    /**Setters*/
    void CVektor3::set(double x,double y,double z)
    {m_x=x;m_y=y;m_z=z;}
    
    void CVektor3::setx(double x)
    {m_x=x;}
    
    void CVektor3::sety(double y)
    {m_y=y;}
    
    void CVektor3::setz(double z)
    {m_z=z;}
    
    /**Vektorfunktionen*/
    /*Betrag*/
    double CVektor3::length()
    {
        double l=sqrt((m_x*m_x)+(m_y*m_y)+(m_z*m_z));
        if (0==l)
            std::cerr << "!!CVektor3::length() returns 0!!";
        return(l);
    }
    /*Einheitsvektor*/
    CVektor3 CVektor3::unit()
    {return(  (*this)/length()  );}
    
    /*Skalarprodukt*/
    double CVektor3::dot(CVektor3 B)
    {return(  m_x*B.m_x + m_y*B.m_y + m_z*B.m_z  );}
    
    /*Kreuzprodukt*/
    CVektor3 CVektor3::kreuz(CVektor3 B)
    {return(  CVektor3(m_y*B.m_z - m_z*B.m_y, m_z*B.m_x - m_x*B.m_z, m_x*B.m_y - m_y*B.m_x)  );}
    
    /*Eingeschlossener Winkel*/
    double CVektor3::winkel(CVektor3 B)
    {return(  acos(dot(B)/(length()*B.length()))  );}
    
    /**Operatorüberladungen*/
    /*Vektor + Vektor*/
    CVektor3 CVektor3::operator+(const CVektor3 B)
    {return(  CVektor3(m_x + B.m_x,m_y + B.m_y,m_z + B.m_z)  );}
    
    /*Vektor - Vektor*/
    CVektor3 CVektor3::operator-(const CVektor3 &B)
    {return(  CVektor3(m_x - B.m_x,m_y - B.m_y,m_z - B.m_z)  );}
    
    /*Vektor + Skalar*/
    CVektor3 CVektor3::operator+(const double &N)
    {return(  CVektor3(m_x + N,m_y + N,m_z + N)  );}
    
    /*Vektor - Skalar*/
    CVektor3 CVektor3::operator-(const double &N)
    {return(  CVektor3(m_x - N,m_y - N,m_z - N)  );}
    
    /*Vektor * Skalar*/
    CVektor3 CVektor3::operator*(const double &N)
    {return(  CVektor3(m_x * N,m_y * N,m_z * N)  );}
    
    /*Vektor / Skalar*/
    CVektor3 CVektor3::operator/(const double &N)
    {return(  CVektor3(m_x / N,m_y / N,m_z / N)  );}
    

    main.cpp falls es jemand testen möchte

    #include <iostream>
    
    #include "cvektor3.h"
    using namespace std;
    
    int main()
    {
        CVektor3 vec1(1,2,3);
        CVektor3 vec2(-7,8,9);
        CVektor3 vecerg;
        double N=4.0;
        double erg;
    
        cout << "Hallo Welt!" << endl;
        cout << "\nVektor 1:\n" << vec1.getx() << '\t' << vec1.gety() << '\t' << vec1.getz();
        cout << "\nVektor 2:\n" << vec2.getx() << '\t' << vec2.gety() << '\t' << vec2.getz();
    
        cout << "\naddition:\n";
        vecerg=vec1+vec2;
        cout << vecerg.getx() << '\t' << vecerg.gety() << '\t' << vecerg.getz();
    
        cout << "\nsubstraktion:\n";
        vecerg=vec1-vec2;
        cout <<vecerg.getx() << '\t' << vecerg.gety() << '\t' << vecerg.getz();
    
        cout << "\nmultiplikation:\n";
        vecerg=vec1*N;
        cout <<vecerg.getx() << '\t' << vecerg.gety() << '\t' << vecerg.getz();
    
        cout << "\ndivision:\n";
        vecerg=vec1/N;
        cout <<vecerg.getx() << '\t' << vecerg.gety() << '\t' << vecerg.getz();
    
        cout << "\nkreuzprodukt:\n";
        vecerg=vec1.kreuz(vec2);
        cout <<vecerg.getx() << '\t' << vecerg.gety() << '\t' << vecerg.getz();
    
        cout << "\nskalarprodukt:\n";
        erg=vec1.dot(vec2);
        cout << erg;
    
        cout << "\nlaenge:\n";
        erg=vec1.length();
        cout << erg << '\n';
        erg=vec2.length();
        cout << erg ;
    
        cout << "\neinheitvektor:\n";
        vecerg=vec1.unit();
        cout <<vecerg.getx() << '\t' << vecerg.gety() << '\t' << vecerg.getz()<< " laenge: " << vecerg.length()<<'\n';
        vecerg=vec2.unit();
        cout <<vecerg.getx() << '\t' << vecerg.gety() << '\t' << vecerg.getz()<< " laenge: " << vecerg.length();
    
        cout << "\nwinkel:\n";
        erg=vec1.winkel(vec2);
        cout <<erg*180/3.14;
    
        return 0;
    }
    


  • Ich hab jetzt nicht alles durchgelesen, aber ich schreibe mal was mir so einfällt.
    (Ich würde Vector als Sonderfall einer Matrix implementieren, das ist aber wohl Overkill hier.)

    Den Grundtyp (double, float) könnte man vielleicht als Template Parameter angeben, ist aber auch kein Muss.

    Getter und Setter würde ich so nicht implementieren. Die Vector Klasse ist doch nicht viel mehr als etwas, was Rechenoperationen zur Verfügung stellt. x, y, z könntest du eigentlich gleich public machen. (Oder du nimmst intern ein Array und bietest double& x() etc. an. Das könnte Sinn machen, wenn du die Größe auch noch von einem Templateparameter abhängig machen willst.) Und da sind wir auch gleich bei dem mysteriösen &. Such mal nach "C++ reference" und vielleicht noch "const correctness", da sollte das erklärt werden.

    Beim Standardkonstruktor würde ich nicht erwarten, dass das mit 0 initialisiert wird, aber das ist wohl etwas kontrovers.

    Den gesamten Rest (alle Operatoren, und length, unit, ..) würde ich als freie Funktion implementieren. Frei nach was keine Methode sein muss (und keine "fundamentale" Eigenschaft des Objekts ausdrückt), sollte besser eine freie Methode sein.



  • Prinzipiell seh ich das ähnlich wie cooky451. Ich würd das Ding auch zu einem Template machen, sodass du einfach float, double, int etc. Vektoren haben kannst.

    Auch würd ich die Koordinaten nicht private machen, sondern einfach ein struct mit public Membern, OOP auf dem Level ist für eine Vektorklasse imo nicht sinnvoll. Getter und Setter sollte man eigentlich überhaupt eher vermeiden und eine Klasse, die sowohl Getter als auch Setter für das selbe Attribut hat ist eigentlich nicht im Sinne der OOP und auch eher selten wirklich sinnvoll...

    Abgesehen davon, fehlen mir die +=, -= etc. Operatoren sowie das unäre - (Negation).

    Funktionen wie length, dot, cross und insbesondere winkel würd ich persönlich eher als freie Funktionen definieren (wenn du Vektor zu einem Template machst, dann als im Klassentemplate definierte friend function), unit würde ich eher normalize nennen, wobei meine Vektoren da zwei Varianten bieten: Einmal eine Methode, die den entsprechenden Vektor normalisiert und einmal eine freie Funktion, die einen entsprechenden Einheitsvektor returned. Const correctness wär auch von großer Wichtigkeit.

    Generell würd ich so einen Mix aus Englisch und Deutsch vermeiden.

    Der Destruktor dieser Klasse tut wohl mit Sicherheit nichts, daher würde ich auch nicht explizit einen definieren. Denn ein expliziter Destruktor, selbst wenn er leer ist, kann den Compiler (z.B. MSVC) dazu veranlassen, unter gewissen Umständen wesentlich langsameren Code zu generieren.

    Wenn du oft einen Vektor auf einen Stream ausgeben willst, wie in deinem Testprogramm, zahlt es sich vielleicht aus, den << Operator dort entsprechend zu überladen.

    Vielleicht noch eine Buchempfehlung: Effective C++ ist Pflicht für jeden, der C++ programmieren will... 😉



  • Dankeschön das war sehr hilfreich.
    Ich euren Rat befolgt und die Funktionen befreit was auch dazu führte das die Skalarmultiplikation jetzt kommutativ ist. 👍
    Der Destruktor sowie Setter und Getter bis auf set(x,y,z) sind rausgeflogen.

    Dort sind noch weitere Anregungen in euren Beiträgen die ich noch durchgehen muss, besonders von Templates habe ich praktisch keine Ahnung.

    Die Suchbegriffe haben mich auch weitergebracht.
    Sehe ich es richtig das Ausdruck wie dieser:

    double length(const CVektor3 &A);
    

    schnelleren Code erzeugt als

    double length(CVektor3 A);
    

    da das Objekt nicht kopiert werden muss? Das heißt diese Art der Parameterübergabe ist bei nicht primitiven Typen(bei denen es egal ist?) zu bevorzugen?



  • Delther schrieb:

    Ich euren Rat befolgt und die Funktionen befreit was auch dazu führte das die Skalarmultiplikation jetzt kommutativ ist. 👍

    Gut beobachtet, das ist unter anderem einer der Hintergedanken davon... 😉

    Delther schrieb:

    Der Destruktor sowie Setter und Getter bis auf set(x,y,z) sind rausgeflogen.

    Würde ich persönlich wenn, dann auch als freie Funktion anlegen. Interessanter Artikel dazu: http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197
    Wobei ich mir in dem Fall überlegen würde, ob ich nicht einfach

    CVektor3 a = CVektor3(x, y, z);
    

    schreibe...

    Btw: Dieses C Präfix für Klassennamen solltest duch auch loswerden. Ist zwar natürlich Geschmackssache, aber imo kein guter Stil. Bei mir heißt das Ding einfach vector<double, 3> (ich schreib Typen mit Wertsemantik meist klein)...

    Delther schrieb:

    Die Suchbegriffe haben mich auch weitergebracht.
    Sehe ich es richtig das Ausdruck wie dieser:

    double length(const CVektor3 &A);
    

    schnelleren Code erzeugt als

    double length(CVektor3 A);
    

    da das Objekt nicht kopiert werden muss? Das heißt diese Art der Parameterübergabe ist bei nicht primitiven Typen(bei denen es egal ist?) zu bevorzugen?

    Ja, so in der Art. Ich würde dir aber empfehlen, dass du dich erstmal noch eingehender mit dem Konzept von Referenzen (sind gewissermaßen ähnlich wie Pointer, aber dann doch auch wieder sehr unterschiedlich) und const beschäftigst, denn das sind absolut wesentliche Grundlagen von C++. Danach kannst du irgendwann mal das hier lesen, wobei das für deine Vektorklasse noch eher kaum Relevanz hat.

    Ich denk, du solltest auf jeden Fall noch ein gutes C++ Grundlagenbuch lesen, wenn du C++ ernsthaft verwenden willst, einfach zur Auffrischung und zum Füllen mancher Lücken.


  • Mod

    Delther schrieb:

    Sehe ich es richtig das Ausdruck wie dieser:

    double length(const CVektor3 &A);
    

    schnelleren Code erzeugt als

    double length(CVektor3 A);
    

    da das Objekt nicht kopiert werden muss?

    Das ist eine sehr allgemeine Aussage, da kann man immer Gegenbeispiele finden. Tendenziell: Ja.

    Man ersetzt eine Komplettkopie einer Datenstruktur mit einer Zeigerkopie. Ist die Datenstruktur größer als ein Zeiger, so ist dies einen Tacken schneller, ist sie viel größer als ein Zeiger ist es sogar viel schneller. Dafür handelt man sich jedoch eine Indirektion beim Zugriff ein, dadurch wird jeder Zugriff einen ganz kleinen Tacken langsamer. Dadurch ist es möglich, Beispiele zu konstruieren, in denen der Kopiervorteil wieder aufgefressen wird. Falls der Kopiervorteil von vornherein klein oder nicht vorhanden war, sind diese Beispiele sogar realistisch.

    Das heißt diese Art der Parameterübergabe ist bei nicht primitiven Typen(bei denen es egal ist?) zu bevorzugen?

    Nicht immer. Faustregel mit der ich bisher ganz gut fahre ist alles über 2-3 Pointergrößen als Referenz zu übergeben, sowie alle Datenstrukturen unbekannter Größe.

    Dein Vektor fällt da genau auf die Grenze, ich würde aber tendenziell die Referenz nehmen. Da die Funktionen sehr einfach sind und daher sowieso inline sein sollten (das solltest du übrigens noch nachholen! Definier deine Einzeilerfunktionen im Header.) darf man da auf komplette Optimierung durch den Compiler hoffen, egal was von beidem man macht.

    P.S.: Statt getter/setter und public-Membern würde ich stattdessen den operator[] überladen.
    P.P.S.: Letzteres macht jedoch erst so richtig Sinn, wenn die Dimension auch flexibel ist. Wenn du dich auf 3er-Vektoren festlegst, dann bleib ruhig bei dem wie es ist.



  • SeppJ schrieb:

    Definier deine Einzeilerfunktionen im Header.) darf man da auf komplette Optimierung durch den Compiler hoffen, egal was von beidem man macht.

    Stimmt, das ist in dem Fall sicherlich eine gute Idee. Ich wollt auch schon darauf hinweisen, aber meiner Erfahrung nach machts bei MSVC dank LTCG keinen Unterschied, der Compiler wird so oder so inlinen. Hast du da vielleicht Erfahrungswerte, wie das mit gcc aussieht? Aber spätestens wenn er das Ding zu einem Template macht, bleibt ihm eh nix andres übrig...


  • Mod

    dot schrieb:

    SeppJ schrieb:

    Definier deine Einzeilerfunktionen im Header.) darf man da auf komplette Optimierung durch den Compiler hoffen, egal was von beidem man macht.

    Stimmt, das ist in dem Fall sicherlich eine gute Idee. Ich wollt auch schon darauf hinweisen, aber meiner Erfahrung nach machts bei MSVC dank LTCG keinen Unterschied, der Compiler wird so oder so inlinen. Hast du da vielleicht Erfahrungswerte, wie das mit gcc aussieht? Aber spätestens wenn er das Ding zu einem Template macht, bleibt ihm eh nix andres übrig...

    Der GCC kann ja auch Linkzeitoptimierung. Ich habe jedoch keine Studien darüber durchgeführt, wie sich Linkzeitoptimierung gegenüber explizitem inline verhält. Bei mir sind solche Funktionen sowieso immer inline, so dass man auch ohne LTO auf der sicheren Seite ist. Wenn ich inlining jedoch explizit ausschalte (selbst wenn andere Optimierungen an bleiben) kann man sofort merken, dass mein üblicher Code gleich um mehrere Größenordnungen langsamer wird. In C++ hat man so oft triviale Funktionen, die einfach nur der Abstraktion dienen. Wenn die auf einmal Laufzeitkosten verursachen, dann haut das richtig rein.

    P.S.: Ein Kollegen, dem ich LTO mal erklärt habe (damals, als das noch neu war), hat sein Programm dadurch angeblich um 670% beschleunigt. Ich kenne seinen Code nicht, aber ich vermute mal, dass dort ein ähnlicher Fall vorlag mit vielen kleinen Funktionen, die nicht inline waren.



  • Außer den Themen, die schon genannt worden sind, habe ich noch ein paar Bemerkungen.

    - Die Methoden

    /*Vektor + Skalar*/
    CVektor3 CVektor3::operator+(const double &N)
    {return(  CVektor3(m_x + N,m_y + N,m_z + N)  );}
    
    /*Vektor - Skalar*/
    CVektor3 CVektor3::operator-(const double &N)
    {return(  CVektor3(m_x - N,m_y - N,m_z - N)  );}
    

    machen mathematisch gar keinen Sinn. Ich habe noch nie eine Anwendung gesehen, wo man so etwas benötigt. Ich würde sie einfach weglassen. Es sei denn, Du erzählst uns wozu sie dienen.

    - Die Methode

    /*Eingeschlossener Winkel*/
    double CVektor3::winkel(CVektor3 B)
    {return(  acos(dot(B)/(length()*B.length()))  );}
    

    sieht harmlos aus, ist aber furchtbar inperformant. In length() wird zwangsläufig die Wurzel (sqrt) aufgerufen. Und das auch noch zweimal. Besser wäre hier

    /*Eingeschlossener Winkel*/
    double CVektor3::winkel(CVektor3 B)
    { return acos(dot(B)/dot(*this)); }
    

    bzw.

    /*Eingeschlossener Winkel*/
    double CVektor3::winkel(CVektor3 B)
    { return acos(dot(*this, B))/dot(*this, *this); }
    

    wenn dot eine Funktion ist und 2 Parameter hätte.
    Damit sparst Du 4 Multiplikationen, zweimal die Wurzel und 2 Additionen, wenn ich mich nicht verrechnet habe.

    - Bei allen Methoden, die das Vektor-Objekt nicht verändern, solltest Du const hinzufügen (const correctness), Das gilt in jeden Fall für eventuelle getter und auch für die Methoden

    /**Vektorfunktionen*/
            double length() const;                 /** Betrag */
            CVektor3 unit() const;                 /** Einheitsvektor*/
            double dot(CVektor3 B) const;          /**Skalarprodukt*/
            CVektor3 kreuz(CVektor3 B) const;      /**Kreuzprodukt*/
            double winkel(CVektor3 B) const;       /**eingeschlossener winkel*/
    

    Das steht auch in dem Buch von Scott Meyers, welches Dir dot empfohlen hat und hier ist auch ein Artikel zum Thema const.

    - Wenn Du bei einer Klasse arithmetische Operator (z.B. + und -) implementierst, die als Ergebnis wieder ein Objekt dieser Klasse haben, so solltest Du auch immer die passenden =-Operatoren hinzufügen. Also hier

    CVektor3& operator+=( const CVektor& b );
    

    Da hierbei natürlich das selbe herauskommen sollte, wie beim operator+ mit zwei Parametern, kannst Du sie auch so implementieren, dass sie sich gegenseitig aufrufen. Wenn der Zuweisungsoperator implementiert wird, so kann die frei Verknüpfung für + z.B. so aussehen

    CVektor3 operator+( CVektor a, const CVektor& b ) {
        return a += b;
    }
    

    Diese Konstruktion hätte aber Nachteile bei der RVO des Compilers. Aber das lass Dir vielleicht von anderen erklären.
    Zum Thema hat pumuckl bereits drei Artikel im C++-Magazin geschrieben und die boost.operators-Lib ist auch noch interessant.

    - Im Gegensatz zu manch' anderen bin ich der Meinung, dass die setter-Methoden beim Vektor völlig überflüssig sind - bei private members versteht sich. Ein CVektor3::set(x,y,z) kann leicht durch

    CVektor3 a = ...;
        a = CVektor(x,y,z);
    

    realisiert werden. Ich bezweifele auch dass das in irgendeiner Weise Performance-Verluste aufweist.

    - hier findest Du noch einen ähnlichen Thread zum Vektor und auch meinen Beitrag dazu.

    Gruß
    Werner



  • .. noch was vergessen:

    #include <math.h>
    

    ist veraltet. Nach dem C++-Standard sollte es #include <cmath> heißen, dann kommen die mathematischen Funktionen in den namespace std. Beim Aufruf von acos oder sqrt muss man dann std::acos bzw std::sqrt schreiben.

    - die Berechnung der Länge des Vektors würde ich als freie (friend)Funktion implementieren und sie abs nennen. Dann ist das äquivalent zu dem std::abs aus <cmath>.

    Gruß
    Werner



  • Werner Salomon schrieb:

    Die Methoden machen mathematisch gar keinen Sinn. Ich habe noch nie eine Anwendung gesehen, wo man so etwas benötigt. Ich würde sie einfach weglassen. Es sei denn, Du erzählst uns wozu sie dienen.

    Da hast du schon recht, ich vermute an der Stelle habe ich MATLAB imitiert.

    Dieses hier verstehe ich nicht und bekomme da auch nicht das Ergebnis heraus:

    Werner Salomon schrieb:

    Besser wäre hier

    /*Eingeschlossener Winkel*/
    double CVektor3::winkel(CVektor3 B)
    { return acos(dot(B)/dot(*this)); }
    

    bzw.

    /*Eingeschlossener Winkel*/
    double CVektor3::winkel(CVektor3 B)
    { return acos(dot(*this, B))/dot(*this, *this); }
    

    wenn dot eine Funktion ist und 2 Parameter hätte.
    Damit sparst Du 4 Multiplikationen, zweimal die Wurzel und 2 Additionen, wenn ich mich nicht verrechnet habe.

    Ich konnte nur eine Wurzel sparen:

    double winkel(const CVektor3 &A,const CVektor3 &B)
    {return(  acos((A*B)/sqrt(A*A*B*B)  ));}
    

    Die Funktion dot() habe ich abgeschafft und dafür den * operator überladen.



  • Delther schrieb:

    Ich konnte nur eine Wurzel sparen:

    double winkel(const CVektor3 &A,const CVektor3 &B)
    {return(  acos((A*B)/sqrt(A*A*B*B)  ));}
    

    stimmt - ich hatte mich da völlig vertan. Deine Lösung ist fast korrekt - klammere noch die Skalarpodukte; also:

    double winkel(const CVektor3 &A,const CVektor3 &B)
    {return(  acos((A*B)/sqrt((A*A)*(B*B))  ));}
    

    sonst ist die Abarbeitung nicht eindeutig. Das Ergebnis ist aber das gleiche.

    Delther schrieb:

    Die Funktion dot() habe ich abgeschafft und dafür den * operator überladen.

    so habe ich es auch gemacht.

    Gruß
    Werner



  • Werner Salomon schrieb:

    wenn dot eine Funktion ist und 2 Parameter hätte.

    Ja fragen wir ihn doch!

    SCNR 🙂



  • meine meinung zum stil: CVektor ist ein furchtbarer bezeichner. das C-präfix nervt, und Vektor ist deutsch. deutsche bezeichner sind die pest. class Vector3 und gut ist. ist natürlich eine geschmacksfrage.

    das ganze zum template zu machen wirft die frage auf, welchen typ funktionen bzw. methoden entgegennehmen sollen, die mit übergebenen vektoren arbeiten? das geht u.u. bis zur gpu runter. müssen das dann auch alles template-funktionen werden?

    ich habe das vor vielen jahren auch mal versucht so zu implementieren, und das vector-template hat sich als eine seuche herausgestellt, die kaum einzudämmen war. alles mögliche wurde zum template. am ende wurde ein typedef vector3<float> vector3f; draus und damit haben alle komponenten gearbeitet. den aufwand, integer- und fließkommazahlen unter einen hut zu bringen, hätte ich mir da sparen können.



  • vektoriant:
    Ich habe in meinem Projekt ein globales typedef namens "UsualVector" als "typedef vector<3, float>". Wenn ich irgendwann merke, dass mir die Präzision nicht reicht, kann ich einfach dieses typedef ändern und float durch double ersetzen. Ich sehe da kein Problem, man muss ja nicht überall den ganzen Templatenamen hinschreiben.


Anmelden zum Antworten