Vererbung und Operatorüberladung



  • @Pneox sagte in Vererbung und Operatorüberladung:

    geht aber auch nicht.

    Heißt was?



  • @Pneox sagte in Vererbung und Operatorüberladung:

     bool skalar(Vec2Dext V1, Vec2Dext V2) {
            if(((x * V1.x) + (y * V2.y)) == 0){
                return true;
            }
            return false;
        }
    

    Hab es so probiert, geht aber auch nicht..

    Das geht doch so noch nicht mal durch den Compiler. Wo kommen denn x und y her?



  • #include <iostream>
    
    using namespace std;
    
    
    class Vec2D {
    
    public:
        double x,y;
    
        //Konstruktor
        Vec2D(double a, double b) : x(a), y(b){}
    
        //Operator überladung "+"
        Vec2D operator+ (Vec2D p) {
            return Vec2D(x + p.x, y + p.y);
        }
    
        //Operator Überladung "<<"
        friend ostream& operator<<(ostream& os, const Vec2D& output){
            os << "<" <<output.x << "," << output.y << ">" <<endl;
            return os;
        }
    
        Vec2D operator* (Vec2D p) {
            return Vec2D(x * p.x, y * p.y);
        }
    };
    
    
    
    class Vec2Dext : public Vec2D{
    
    public:
    
        //Konstruktor
        Vec2Dext(double a, double b) : Vec2D(a,b){}
    
        bool skalar(Vec2Dext V1, Vec2Dext V2) {
            if(((x * V1.x) + (y * V2.y)) == 0){
                return true;
            }
            return false;
        }
    };
    
    
    
    int main() {
    
        Vec2Dext Vek1(2,-2);
        Vec2Dext Vek2(3,3);
    
        Vec2D ErgebnisAdd = Vek1 + Vek2;
    
        cout<<ErgebnisAdd;
    
        Vec2D ErgebnisMulti = Vek1 * Vek2;
    
        cout<<ErgebnisMulti;
    
    
        if (Vek1.skalar(Vek1, Vek2)){
            cout<<"JA";
        }
        else{
            cout<<"Nein";
        }
    
        return 0;
    }
    

    So hier nochmal alles bis zum jetzigen Zeitpunkt.

    Bei den Vektoren kommt "NEIN" raus, obwohl das Skalarprodukt hier gleich "0" ist.

    Vielleicht ist es auch eine Kleinigkeit die ich übersehe.



  • Wie wäre es, wenn Du skalar() const zu einem Member von Vec2Dext machst und nur einen Vec2 (als konstante Referenz) als Parameter nimmst? Dann würde die Verwendung von x und y passen.

    @Pneox sagte in Vererbung und Operatorüberladung:

    if(((x * V1.x) + (y * V2.y)) == 0){

    Kann nicht passen, weil jetzt sind schon 3 Vektoren im Spiel: Der, für den skalar() aufgerufen wird (x und y), V1 (V1.x und V1.y) und V2 (V2.x und V2.y).

    @Swordfish sagte in Vererbung und Operatorüberladung:

    return (x * other.x + y * other.y) == 0; // edit: Oh, doubles. Dann lieber prüfen ob das Ergebnis klein genug ist.

    Bei deinen im Beispiel gewählten "schönen" Zahlen mag ein direkter Vergleich mit 0 noch gutgehen, aber in der Regel muss man beachten, daß Fließkommazahlen nicht beliebig genau sind und es zu Abweichungen im Ergebnis kommen kann. Deshalb kann es schon mal vorkommen, daß etwas, das im Dezimalsystem mit beliebiger Genauigkeit genau 0 ist, mit floats oder doubles nicht genau 0 ist sondern eine sehr kleine Zahl <> 0.



  • #include <iostream>
    
    using namespace std;
    
    
    class Vec2D {
    
    public:
        double x,y;
    
        //Konstruktor
        Vec2D(double a, double b) : x(a), y(b){}
    
        //Operator überladung "+"
        Vec2D operator+ (Vec2D p) {
            return Vec2D(x + p.x, y + p.y);
        }
    
        //Operator Überladung "<<"
        friend ostream& operator<<(ostream& os, const Vec2D& output){
            os << "<" <<output.x << "," << output.y << ">" <<endl;
            return os;
        }
    
        Vec2D operator* (Vec2D p) {
            return Vec2D(x * p.x, y * p.y);
        }
    };
    
    
    
    class Vec2Dext : public Vec2D{
    
    public:
    
        //Konstruktor
        Vec2Dext(double a, double b) : Vec2D(a,b){}
    
        bool skalar(Vec2Dext V2) {
            int u;
            u =((x * V2.x) + (y * V2.y));
    
            if ( u == 0 ){
                return true;
            }
    
    
            return false;
        }
    };
    
    
    
    int main() {
    
        Vec2Dext Vek1(3.8,-3.8);
        Vec2Dext Vek2(6.7,6.7);
    
        Vec2D ErgebnisAdd = Vek1 + Vek2;
    
        cout<<ErgebnisAdd;
    
        Vec2D ErgebnisMulti = Vek1 * Vek2;
    
        cout<<ErgebnisMulti;
    
    
        if (Vek1.skalar(Vek2)){
            cout<<"JA";
        }
        else{
            cout<<"Nein";
        }
    
        return 0;
    }
    

    So jetzt funktioniert es!

    Dankeschön an alle 🙂



  • #include <limits>
    #include <cmath>
    
    // ...
    
    bool Vec2Dext::skalar(Vec2Dext const &V2) const
    {
        return std::fabs(x * V2.x + y * V2.y) < std::numeric_limits<double>::epsilon(); // *)
    }
    

    * ) Ja, nicht optimal, aber schonmal besser als == 0.



  • Sauber! Und jetzt machen wir das noch schön 😉

    • da du Vec2D als Basisklasse für Vec2Dext benutzt solltest du einen virtuellen Destruktor für Vec2D bereitstellen
    • Parameter, auf die nur lesend zugegriffen werden, sollten als const reference übergeben werden
    • Funktionen, deren Ergebnisse nicht von Membern einer Klasse abhängen, sollten als freie Funktionen implementiert werden. Es gibt keinen Grund, warum skalar in seiner jetzigen Form als Member implementiert wird.


  • @DocShoe sagte in Vererbung und Operatorüberladung:

    Es gibt keinen Grund, warum skalar in seiner jetzigen Form als Member implementiert wird.

    Naja, schon:

    @Pneox sagte in Vererbung und Operatorüberladung:

    Mein Problem ist jetzt, dass ich in der zweiten Klassen die von der ersten vererbt ist eine Methode erstellen soll, die prüft ob die beiden Vektoren orthogonal zu einander liegen.

    😜



  • Es gibt keinen Grund, warum skalar in seiner jetzigen Form 2 Parameter erwartet. Die beiden Vektoren sind das Objekt selbst, auf dem skalar aufgerufen wird, und der zweite wird als einziger Parameter übergeben. Aber das hat swordfish ja schon gezeigt.

    Besser? 😁



  • @DocShoe yay 👍 😇



  • @DocShoe sagte in Vererbung und Operatorüberladung:

    Sauber! Und jetzt machen wir das noch schön 😉

    • da du Vec2D als Basisklasse für Vec2Dext benutzt solltest du einen virtuellen Destruktor für Vec2D bereitstellen

    Ich bin mir etwas unschlüssig, ob man nicht lieber erwähnen sollte, dass Polymorphie ein C++ ein optionales Feature ist und man einen virtuellen Destruktor nur dann benötigt, wenn es auch nutzt. Wahrscheinlich fahren Anfänger aber besser, wenn sie Vererbung erstmal nur mit polymorphen Klassen machen, das könnte helfen Überraschungen zu vermeiden.

    Mit dem virtuellen Destruktor macht man jedenfalls erstmal nichts falsch - man sollte ihn nur dann weglassen, wenn man weiss, warum man es tut 😉


Anmelden zum Antworten