Probleme mit Vererbung beim Gauß-Algorithmus



  • Hallo zusammen,
    ich sitze seit Stunden an folgendem Problem:
    Wir sollen den Gauß-Algorithmus programmieren und ich wollte mir durch Vererbung eine Variable (Spaltenbreite) sparen. Also Matrix als Elternklasse und Zeile davon abgeleitet.
    Ich musste Matrix.h in Zeile.h einbinden und umgekehrt, was ja eigentlich nicht geht.
    Das Problem habe ich jetzt glaube ich irgendwie hinbekommen. (durch Raten)
    Ich habe das halbe Internet abgesucht wo man welche header Datei einbinden muss. Aber es hat irgendwie nichts geklappt.
    Mein nächstes Problem sind jetzt die Konstruktoren.
    Ich muss den ifstream anscheinend irgendwie im default Konstruktor initialisieren aber ich weiß nicht wie. Ich bekomme immer folgende Fehlermeldungen.

    Matrix.cpp:26:1: error: uninitialized reference member in 'std::ifstream& {aka class std::basic_ifstream<char>&}' [-fpermissive]
    Matrix.h:16:15: note: 'std::ifstream& Matrix::f_in' should be initialized

    Außerdem bin ich mir mit den #include Anweisungen und der Vererbung noch nicht sicher ob das so geht.

    Wäre super wenn mir einer helfen könnte.

    
    #ifndef MATRIX_H
    #define MATRIX_H
    
    using namespace std;
    
    //#include "Zeile.h"
    #include <string>
    #include <vector>
    
    class Zeile;
    
    class Matrix {
    private:
        vector<Zeile> matrixVec;
        ifstream& f_in;
    protected:
        uint zeilenDim, spaltenDim;
    public:
        static bool zeigeZwischenergebnisse;
        //Standardkonstruktor
        Matrix();
        //Konstruktor
        Matrix(uint _zeilenDim, uint _spaltenDim, ifstream& _f_in);
        //Copy-Konstruktor
        //Matrix(const Matrix& orig);
        //Getter-Methoden
        const uint& gib_n() const;
        const uint& gib_m() const;
        //Operatorueberladungen
        friend ostream& operator<<(ostream& out, const Matrix& printMatrix);
        Matrix& operator=(const Matrix& orig);
    
        //Methoden
        Matrix reduzierteStufenform() const;
        static void protokoll_aus();
        
        //virtual ~Matrix();
    
    };
    
    #endif /* MATRIX_H */
    
    //    void set_data ( const my_class & date)
    //    {
    //        m_data= data;
    //    }
     ... Code ... 
    
    
    #ifndef ZEILE_H
    #define ZEILE_H
    
    using namespace std;
    
    #include"Matrix.h"
    
    #include<fstream>
    #include<string>
    #include<vector>
    
    
    class Zeile: public Matrix {
    private:
        //uint zeilenDim; 
        bool varistNullzeile;
    public:
        vector<double> zeilenElemente;
        //Defaultkonstruktor
        Zeile();
        
        Zeile (uint _zeilenLaenge, ifstream& _f_in);
        //Operatorueberladungen
        double operator[] (uint  zeilenIndex);
        Zeile& operator+= (const Zeile& orig);
        Zeile& operator*= (const double faktor);
        
        //Methoden
        Zeile& Einlesen (uint _zeilenLaenge, ifstream& _f_in);
        bool istNullzeile();
    
        //Zeile(const Zeile& orig);
    //    virtual ~Zeile();
    
        
    };
    
    #endif /* ZEILE_H */
    
    
     ... Code ... 
    
    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    
    /* 
     * File:   Matrix.cpp
     * Author: phili
     * 
     * Created on 10. Oktober 2018, 20:53
     */
    
    //#include "Matrix.h"
    #include "Zeile.h"
    
    #include <vector>
    #include <algorithm>
    #include <iostream>
    #include <iomanip>
    
    //class Zeile;
    
    #define debug
    
    Matrix::Matrix() {
    }
    
    Matrix::Matrix(uint _zeilenDim, uint _spaltenDim, ifstream& _f_in) : zeilenDim(_zeilenDim), spaltenDim(_spaltenDim), f_in(_f_in){
       
        for(uint i=0; i<zeilenDim; i++){
    
            Zeile tempZeile(_spaltenDim,_f_in);
            this->matrixVec.push_back(tempZeile);
        }
    }
    
    Matrix Matrix::reduzierteStufenform() const{
            
       Matrix reduzMatrix = *this; //Tiefe Kopie im Copy-Konstruktor anlegen
     
       Zeile *pivotZeilePtr = &reduzMatrix.matrixVec.at(0);
       
       for(uint spaltenIndex=0; spaltenIndex<spaltenDim; spaltenIndex++) {
     
        double pivotElement = (*pivotZeilePtr)[spaltenIndex];
        
        int positionPivotzeile = distance(&reduzMatrix.matrixVec.at(0), pivotZeilePtr); 
    
        //PivotZeile suchen
        for (uint i=0 ;i<zeilenDim; i++){
            if(pivotElement!=0) break;
            else pivotZeilePtr++;
        }
     
        //Zeile mit der obersten tauschen
        swap(reduzMatrix.matrixVec[positionPivotzeile],reduzMatrix.matrixVec[0]);
    
        //in der pivotSpalte aller darunter liegenden Zeilen Nullen erzeugen
        for(vector<Zeile>::iterator it= reduzMatrix.matrixVec.begin(); it!= reduzMatrix.matrixVec.end(); it++){
              
    //                *pivotZeilePtr *= (-pivotElement);
    //                *it += *pivotZeilePtr;
        } 
        
        
    //    //Nullzeile ganz nach unten tauschen
    //    if (*pivotZeilePtr->istNullzeile()) iter_swap(posIt , reduzMatrix.matrixVec.back());
        
        }
    return reduzMatrix;
    
    }
    
    
    //Getter-Methoden
    const uint& Matrix::gib_n() const{
        return this->zeilenDim;
        }
    
    const uint& Matrix::gib_m() const{
        return this->spaltenDim;
        }
    
        void Matrix::protokoll_aus(){
             Matrix::zeigeZwischenergebnisse=true;
        }
           
    //Zeile Matrix::operator [](uint spaltenIndex){
    //    if (zeilenIndex > 2) throw ("falscher SpaltenIndex");
    //    return this->zeilenElemente.at(zeilenIndex-1);
    //}  
     
    ostream& operator<<(ostream& out, const Matrix& printMatrix){
        
        for(uint i=0; i<printMatrix.zeilenDim; i++){
            vector<double> tempVector = printMatrix.matrixVec.at(i).zeilenElemente;  
            for(uint j=0; j<printMatrix.spaltenDim; j++){
              cout << setw(7)<< tempVector[j] ;
            }
            cout << endl;
        }
        
        return out;
        }
      
        Matrix& Matrix::operator=(const Matrix& orig){
        
        if (this != &orig){      
        matrixVec.assign(orig.matrixVec.begin(), orig.matrixVec.end());
        spaltenDim = orig.spaltenDim;
        zeilenDim = orig.zeilenDim;
        zeigeZwischenergebnisse = orig.zeigeZwischenergebnisse;
            }
        return *this;
        
        }
    
    
    
    //Matrix::Matrix(const Matrix& orig) {   
    //}
    
    
    /*
    Matrix::~Matrix() {
    }
    */
    
     ... Code ... 
    
    
    #include <vector>
    #include <algorithm>
    #include <string>
    #include <iostream>
    
    #include "Zeile.h"
    //#include "Matrix.h"
    
    
    Zeile::Zeile() {
    }
    
    Zeile::Zeile (uint _zeilenLaenge, ifstream& _f_in) {
        this->Einlesen(_zeilenLaenge, _f_in);
    }
    
    
    double Zeile::operator [](uint zeilenIndex){
        if (zeilenIndex>this->spaltenDim) throw string ("falscher Zeilenindex operator []");
        return this->zeilenElemente.at(zeilenIndex);
    }
    
    Zeile& Zeile::Einlesen (uint _zeilenLaenge, ifstream& f_in){
        
        this->spaltenDim=_zeilenLaenge;
        
        for (uint i=0; i<_zeilenLaenge; i++){
            //Vektor Nummernweise fuellen  
            string element;
            f_in >> element;    
            
            
          //Ausnahme werfen 
          //if (element == "\n" || element == "") throw string("Falscher Zeilenindex");
         //if (element.find_first_not_of("0123456789-+.") != string::npos) throw string(element + " ist keine gueltige Zahl");
       
        
         double elemDouble = strtod(element.c_str(), NULL);
         this->zeilenElemente.push_back(elemDouble); //
    
        }
    
        return *this;
                
    }
    
    bool Zeile::istNullzeile(){
        return all_of(this->zeilenElemente.begin(), this->zeilenElemente.end(), [](int i) { return i==0; });
    }
    
    
    
    
    Zeile& Zeile::operator+=(const Zeile& orig){
      if (this->spaltenDim != orig.spaltenDim) throw string ("Dimensionen passen nicht +=");
        else{
           //Zeilen Addieren
            for (uint i=0; i<this->spaltenDim; i++){
                this->zeilenElemente.at(i) += orig.zeilenElemente.at(i);
            }
        }  
      return *this;
    }
    
    Zeile& Zeile::operator*= (const double faktor){
        for (uint i=0; i<this->spaltenDim; i++){
                this->zeilenElemente.at(i) *= faktor;
            }
        return *this;
    }
    
    
    /*
    Zeile::~Zeile() {
    }
    
    
    Zeile::Zeile(const Zeile& orig) {
       
    }
     * /
     ... Code ... 
    
    #define debug
    
    #include "Matrix.h"     // Matrixzeilen
    #include "Zeile.h"      // Matrizen  
    
                                
    bool Matrix::zeigeZwischenergebnisse=true;     // Protokoll an
    typedef unsigned int uint;
    
    #include<iostream>
    #include<fstream>
    using namespace std;
    
    
    int main() {
      ifstream f_in;
      f_in.open("Matrixdaten");
    
      cout << "Zeilentest" << endl;
      cout << "----------" << endl;
      Zeile z1,z2;
      try {
        z1.Einlesen(3,f_in);
        z2.Einlesen(4,f_in);
        cout << z1[2] << endl;                      // unzulaessiger Indexwert
      }
      catch (string& fehlertext) {
        cout << "!!! " << fehlertext << endl;
      }
      
      try {
        z1+=z2;                                     // Dimensionen passen nicht
      }
      catch (string& fehlertext) {
        cout << "!!! " << fehlertext << endl;
      }
      cout << endl << endl;
      
    
      cout << "Matrixtest" << endl;
      cout << "----------" << endl; 
      try {
        Matrix A(4,5,f_in);
        cout << "A: " << A.gib_m() << "x" << A.gib_n() << endl;
        cout << A << endl;
        Matrix StufeA(A.reduzierteStufenform());
        cout << "Stufenform: " << endl;
        cout << StufeA << endl;
        cout << endl<< "---------------------" << endl << endl;
        getchar();
    
    //    Matrix::protokoll_aus();                   // Ab jetzt Protokoll aus
    //    Matrix B(3,2,f_in);
    //    cout << "B: " << B.gib_m() << "x" << B.gib_n() << endl;
    //    cout << B << endl;
    //    Matrix StufeB(B.reduzierteStufenform());
    //    cout << "Stufenform: " << endl;
    //    cout << StufeB << endl;
    //    cout << endl<< "---------------------" << endl << endl;
    //    getchar();
    //
    //    Matrix C(2,3,f_in);
    //    cout << "C: " << C.gib_m() << "x" << C.gib_n() << endl;
    //    cout << C << endl;
    //    Matrix StufeC(C.reduzierteStufenform());
    //    cout << "Stufenform: " << endl;
    //    cout << StufeC << endl;
     
    }
      catch (string& fehlermeldung) { cout << "!!!  " << fehlermeldung << endl; }
    
      f_in.close();
    return 0;
    }
     ... Code ... 
    


  • Laß den Standard-Konstruktor weg, denn dieser macht ja keinen Sinn (du müßtest ja auch die Matrixdimensionen dann mit einem Standardwert initialisieren).

    Es macht aber auch generell keinen Sinn, ifstream& f_in als Klassenmember zu halten.
    Zur Ein- und Ausgabe gibt es ja die Streamoperatoren >> und <<.

    PS:
    Philipp2706 schrieb:

    Also Matrix als Elternklasse und Zeile davon abgeleitet.

    Eine Zeile ist aber keine Matrix!

    PPS: Und niemals using namespace std; in Headerdateien!!!



  • @th69 Ja stimmt, habe ich mir auch so gedacht.
    Aber das Hauptprogramm ist leider so vorgegeben. Und da werden zwei Zeilen über den Standard-Konstruktor erzeugt.
    (Zeile z1,z2;)
    Ich habe auch schon probiert den Defaultkonstruktor von Matrix im Defaultkonstruktor von Zeile aufzurufen.
    Vielleicht ist Vererbung hier wirklich nicht so gut geeignet. Ich würde aber gerne nur eine Variable für die Spalten Dimension haben.
    Also nur einmal als Attribut in Matrix, und nicht in Matrix und Zeile jeweils ein Attribut dafür.
    Wie mach ich das denn am besten?



  • Ich hatte noch mal oben nacheditiert (während du gepostet hattest).

    Da also der Code der main-Funktion vorgegeben ist, lösche also ifstream& _f_in als Konstruktorparameter (dort wird es ja auch nicht verwendet, sondern nur direkt bei der Einlesen-Funktion).

    Ich muß jetzt weg, aber schaue später hier noch mal rein...



  • @philipp2706 sagte in Probleme mit Vererbung beim Gauß-Algorithmus:

    ich wollte mir durch Vererbung eine Variable (Spaltenbreite) sparen.

    brr..... Das ist das falsche Argument für Vererbung. Immer. Vererbung sollte so benutzt werden, dass man die Unterklasse auch als Oberklasse benutzen kann (und wo du wirklich sagen kannst "ist ein")

    Ist der Matix-Kram so vorgegeben?
    Ansonsten ist es meistens (außer vielleicht bei einer großen, fast überall leeren Matrix) sinnvoll, sie als ein einzigen Vector mit spalten*zeilen Elementen zu speichern - einfach erste Zeile, zweite Zeile, ... hintereinander. Du hast als member also einen vector die Spalten- und Zeilenanzahl. Du kannst dir dann leicht eine Zeile holen - die ja dann ja nur ein view auf einen bestimmten Bereich des Vectors (natürlich kannst du den vector auch umgekehrt, also Spalten hintereinander speichern, dann sind views auf Spalten kostenlos)



  • Ja ihr habt Recht die Idee mit Vererbung war quatsch. Ich werde es jetzt so lösen dass ich im Konstruktor von Zeile die Spalten Dimension der Matrix mitgebe
    und einfach in Zeile und Spalte ein Attribut zeilenDimension behalte.
    Vielen Dank🙂