Search code examples
c++inheritanceoperator-overloadingdynamic-memory-allocation

Troubleshooting read/write access to protected variables in C++ inheritance and operator overloading


I have the problem that in the int main() (at the point where the comments are) my vectors are created but not displayed on the console.

Main():

#include "matrix.h"
#include "Spaltenvektor.h"
#include "Zeilenvektor.h"
#include <iostream>
using namespace std;

void belegen_m1(Matrix& m)
{
    double cmat[5][3] = { { 1.0, 0.0, 0.0 },
                          { 0.0, 2.0, 0.0 },
                          { 0.0, 0.0, 3.0 },
                          { 4.0, 0.0, 0.0 },
                          { 0.0, 5.0, 0.0 }
    };
    for (int z = 0; z < m.zeilen(); z++)
        for (int s = 0; s < m.spalten(); s++)
            if (m.setze_element(z, s, cmat[z][s]) == 0)
            {
                cout << "Fehler bei belegen_m1(), Abbruch" << endl;
                exit(EXIT_FAILURE);
            }


}
void belegen_m2(Matrix& m)
{
    double cmat[3][5] = { { 1.0, 0.0, 0.0, 4.0, 0.0 },
                          { 0.0, 2.0, 0.0, 0.0, 5.0 },
                          { 0.0, 0.0, 3.0, 0.0, 0.0 }
    };
    for (int z = 0; z < m.zeilen(); z++)
        for (int s = 0; s < m.spalten(); s++)
            if (m.setze_element(z, s, cmat[z][s]) == 0)
            {
                cout << "Fehler bei belegen_m2(), Abbruch" << endl;
                exit(EXIT_FAILURE);
            }

}

Matrix erzeuge_quadr_testmatrix(int n)
{
    Matrix test(n, n);
    for (int z = 0; z < test.zeilen(); z++)
        for (int s = 0; s < test.spalten(); s++)
            if (test.setze_element(z, s, z * test.zeilen() + s) == 0)
            {
                cout << "Fehler bei erzeuge_quadr_testmatrix(), Abbruch" << endl;
                exit(EXIT_FAILURE);
            }
    return test;
}


int main()
{
    Matrix m1(5, 3), m2(3, 5);
    Matrix m3, m4, m5, m6, m7;

    belegen_m1(m1);

    belegen_m2(m2);

    cout << "m1:" << endl << m1 << endl;
    cout << "m2:" << endl << m2 << endl;

    m3 = m1.transpos();

    cout << "m3= m1.transposition():" << endl << m3 << endl;

    if (m3.transpos() == m1)
    {
        cout << "Zweifache Transposition ergibt wieder die Originalmatrix." << endl;
    }
    else
    {
        cout << "Nach zweifacher Transposition ergibt sich keine Originalmatrix, Fehler in Methode transposition()" << endl;
        exit(EXIT_FAILURE);
    }

    m3 = m3.transpos();
    cout << "m3= m3.transpos():" << endl << m3 << endl;

    m4 = m1 + m3;

    cout << "m4 = m1+m3:" << endl << m4 << endl;;

    m5 = m1 * m2;

    cout << "m5=m1*m2:" << endl << m5 << endl;

    m6 = m2 * m1;

    cout << "m6=m2*m1:" << endl << m6 << endl;

    m7 = m5 * m6;

    cout << "m7=m5*m6:" << endl << m7 << endl;

    Matrix v1(1, 10), v2(10, 1), s;
    for (int i = 0; i < v1.spalten(); i++)
        v1.setze_element(0, i, (double)i);
    for (int i = 0; i < v2.zeilen(); i++)
        v2.setze_element(i, 0, (double)i);
    s = v1 * v2;

    cout << "v1: " << v1 << endl;
    cout << "v2: " << endl << v2 << endl;
    cout << "Zeilenvektor v1 * Spaltenvektor v1 ..." << endl;
    cout << s << endl;

    m7 = erzeuge_quadr_testmatrix(4);
    cout << "Ausgabe quadratische Testmatrix:" << endl << m7 << endl;


    cout << "_________________________ Beginn der Erweiterung E1 _________________________" << endl;
    Zeilenvektor V1(10);
    Spaltenvektor V2(10);
    Matrix S;

    for (int i = 0; i < V1.spalten(); i++)      // the values are set in each vector 
        V1.setze_element(0, i, (double)i);
    for (int i = 0; i < V2.zeilen(); i++)
        V2.setze_element(i,0, (double)i);
                                                // the problem starts here
    S = V1 * V2;                                // maybe not working or also dosent show the result

    cout << "v1: " << endl << V1 << endl;       // the vectors are created but not displayed in the console 
    cout << "v2: " << endl << V2 << endl;
    cout << "Zeilenvektor v1 * Spaltenvektor v1 = " << endl;
    cout << S << endl;

    return EXIT_SUCCESS;
}

Matrix.h ( From this class inherit the classes rowvector and columnvector. )

#pragma once
#include <iostream>
using namespace std;

class Matrix
{
private:
    //int Zeile, Spalte;
    //double** werte;
protected:
    int Zeile, Spalte;
    double** werte;


public:
    Matrix();
    Matrix(int zeilen, int spalten);
    Matrix(const Matrix& m);                  // Copy-Konstruktór
    virtual ~Matrix();

    Matrix& operator=(const Matrix& M);         // Zuweisungsoperator

    // Methode setze_element(): setzt wert an angegebener Zeile und Spalte
    // Rückgabe 1 wenn erfolgreich, Rückgabe 0 falls Zeile und Spalte ausserhalb 
    // des gültigen Bereichs liegt
    int setze_element(int zeile, int spalte, double Wert_setzen);


    // Methode lese_element(): gibt Wert von angegebener Zeile und Spalte zurück.
    // Falls Zeile und Spalte ausserhalb des gültigen Bereichs liegt, dann Rückgabe von 0
    // und erfolg 0.
    // erfolg signalisiert einen gültigen zurückgegebenen Wert mit 1.  
    double lese_element(int zeile, int spalte, int& erfolg) const;

    // Methode gueltig gibt 0 (für ungültig) zurück, wenn das Matrixobjekt durch eine unzulässige 
    // mathematische Operation entstanden ist, bespielsweise durch Addition von Matrizen unterschiedlicher Größe 
    //int gueltig() const;

    // Methoden zeilen() und spalten() geben die jeweilige Anzahl der Zeilen und Spalten zurück
    int zeilen() const;
    int spalten() const;

    // Mathematische Operationen
    Matrix transpos();
    Matrix operator +(const Matrix& m) const;
    Matrix operator *(const Matrix& m) const;

    // Vergleichsoperator
    int operator ==(const Matrix& m) const;
    friend ostream& operator << (ostream& stream, Matrix& m);

    
    
};

Matrix Matrix::transpos()   // r = row = zeile / c = col = Spalte
{
    Matrix MT(Spalte, Zeile);

    for (int r = 0; r < Zeile; r++)
    {
        for (int c = 0; c < Spalte; c++)
        {
            MT.werte[c][r] = werte[r][c];
        }
    }
    cout << endl;

    return MT;
}

Matrix Matrix::operator*(const Matrix& M) const
{
    Matrix Merg(Zeile, M.Spalte);
    cout << endl;

    if (Spalte != M.Zeile && Zeile != M.Spalte)
    {
        cout << "UNGUELTIG!" << endl;
        cout << endl;
        return Merg;
    }

    for (int r = 0; r < Zeile; r++)
    {
        for (int c = 0; c < M.Spalte; c++)
        {
            for (int i = 0; i < Spalte; i++)
            {
                Merg.werte[r][c] = (werte[r][i] * M.werte[i][c]) + Merg.werte[r][c];
            }
        }
    }

    return Merg;
}

Matrix Matrix::operator+(const Matrix& M) const
{
    Matrix Merg(Zeile, M.Spalte);
    cout << endl;

    if (Zeile != M.Zeile && Spalte != M.Spalte)
    {
        cout << "UNGUELTIG!" << endl;
        cout << endl;
        return *this;
    }

    for (int r = 0; r < Zeile; r++)
    {
        for (int c = 0; c < Spalte; c++)
        {
            Merg.werte[r][c] = werte[r][c] + M.werte[r][c];
        }
    }
    return Merg;
}

Matrix::Matrix(const Matrix& M) //Copy
{
    Spalte = M.Spalte;
    Zeile = M.Zeile;

    if (M.werte)
    {
        werte = new double* [Zeile];

        for (int r = 0; r < Zeile; r++)
        {
            werte[r] = new double[Spalte];

            for (int c = 0; c < Spalte; c++)
            {
                werte[r][c] = M.werte[r][c];
            }
        }

    }
}

Matrix& Matrix::operator=(const Matrix& M)
{
    if (this == &M)
    {
        return *this;
    }

    delete[] werte;
    Zeile = M.Zeile;
    Spalte = M.Spalte;
    werte = new double* [Zeile];

    for (int r = 0; r < Zeile; r++) 
    {
        werte[r] = new double[Spalte];
        for (int c = 0; c < Spalte; c++) 
        {
            werte[r][c] = M.werte[r][c];
        }
    }

    return *this;
}

int Matrix::operator==(const Matrix& M) const
{
    if (Zeile == M.Zeile && Spalte == M.Spalte)
    {
        for (int r = 0; r < Zeile; r++)
        {
            for (int c = 0; c < Spalte; c++)
            {
                if (werte[r][c] != M.werte[r][c] && fabs((werte[r][c] - M.werte[r][c])) > 1e-10)
                {
                    return 0;
                }
            }
        }
    }
    if (Zeile != M.Zeile || Spalte != M.Spalte)
    {
        cout << "Die Matritzen sind nicht gleich gross und koennen nicht identisch sein." << endl;
        return 0;
    }

    return 1;
}

Matrix::Matrix()
{
    Zeile = Spalte = 0;
    werte = NULL;       //Null-pointer
}

ostream& operator << (ostream& stream, Matrix& m)
{
    for (int r = 0; r < m.Zeile; r++) {
        for (int c = 0; c < m.Spalte; c++)
        {
            stream << m.werte[r][c] << "\t";        // here is something wrong when i build
        }
        stream << endl;
    }
    return stream;
}

double Matrix::lese_element(int zeile, int spalte, int& erfolg) const
{
    if (zeile < this->Zeile && spalte < this->Spalte)
    {
        cout << "In der [Zeile / Spalze]: " << "[" << zeile << " / " << spalte << "]" << " befindet sich der Wert: " << werte[zeile - 1][spalte - 1] << endl;
        erfolg = 1;
        return erfolg;
    }
    else
    {
        cout << "Der gesuchte Wert in [Zeile / Spalte]: " << "[" << zeile << " / " << spalte << "]" << " liegt ausserhalb der Matrix." << endl;
        erfolg = 0;
        return erfolg;
    }
}

int Matrix::setze_element(int zeile, int spalte, double Wert_setzen)
{
    if (zeile < Zeile && spalte < Spalte)
    {
        werte[zeile][spalte] = Wert_setzen;
        return 1;
    }
    else
    {
        cout << "Wert Ausserhalb der Matrix. Abbruch!" << endl;
        return 0;
    }
}

Matrix::~Matrix()
{
    if (werte)
    {
        for (int r = 0; r < Zeile; r++)
        {
            delete[] werte[r];
        }
        delete[] werte;
    }
}

int Matrix::spalten()const
{
    return this->Spalte;
}

int Matrix::zeilen() const
{
    return this->Zeile;
}

Matrix::Matrix(int zeilen, int spalten)
{
    this->Spalte = spalten;
    this->Zeile = zeilen;

    werte = new double* [Zeile];
    for (int r = 0; r < Zeile; r++)
    {
        werte[r] = new double[Spalte];
    }

    double init_mit = 0;

    for (int r = 0; r < Zeile; r++)
    {
        for (int c = 0; c < Spalte; c++)
        {
            werte[r][c] = init_mit;
        }
    }
}

Zeilenvektor.h

#pragma once
using namespace std;
#include <iostream>
#include"matrix.h"

class Zeilenvektor :public Matrix
{
public:
    Zeilenvektor();
    Zeilenvektor(int Spalte);

private:
};

Zeilenvektor::Zeilenvektor()
{
}

Zeilenvektor::Zeilenvektor(int Spalten = 0) : Matrix(0, Spalten)
{
}

Spaltenvektor.h

#pragma once
using namespace std;
#include <iostream>
#include"matrix.h"

class Spaltenvektor: public Matrix
{
public:
    Spaltenvektor();
    Spaltenvektor(int Zeile);

private:
};

Spaltenvektor::Spaltenvektor()
{
}

Spaltenvektor::Spaltenvektor(int Zeilen = 0) : Matrix(Zeilen, 0)
{
}

I have tried to find out if I am doing something wrong in the inheritance or if the protected variables in the Matrix.h are denying read/write access. However, I have no solution idea or idea where the problem is.


Solution

  • This is wrong

    Zeilenvektor::Zeilenvektor(int Spalten = 0)
    {
        Spalte = Spalten;
        Matrix M(0, Spalten);
    }
    

    it should be

    Zeilenvektor::Zeilenvektor(int Spalten = 0) : Matrix(0, Spalten)
    {
    }
    

    Your version creates a local variable called M. This has no effect on the base class at all, instead the base class is being created by calling the default constructor. My version calls the correct base class constructor.

    It's been suggested (see comments below) that the 0 here should be a 1, i.e.

    Zeilenvektor::Zeilenvektor(int Spalten = 0) : Matrix(1, Spalten)
    {
    }
    

    but only you can know if this is really the case.

    Also this is wrong

    Zeilenvektor::Zeilenvektor(const Zeilenvektor& Z)
    {
    }
    

    This class does not call the copy constructor for the base class. As with the previous example the base class is being initialised with the default constructor, not with a copy of Z. Since the default constructor does everything correctly you can just remove this code.

    Both these errors seem to indicate that you are not familiar with initialiser lists. You really need to understand how these work to program with classes in C++. Especially when you start using inheritance, because an initialiser list is the way to call the base class constructor.

    Finally this is unnecessary

    Zeilenvektor::~Zeilenvektor()
    {
    }
    

    It's not a bug but since it does nothing it should be removed.

    Looks like you have the exact same errors with Spaltenvektor.