Forum: PC-Programmierung Operator+ overloading, 2D Vector


von Michael S. (michaelsmith)


Lesenswert?

Hallo,

ich habe ein Problem mit dem operator overloading.
ich habe 2 Matrizen die ich in der main() addieren möchte,

Matrix x;
Matrix y;
Matrix result;

// eingabe wird über cin>> gehandelt...
x.a[2][2] = {{2, 2}, {2, 2}}
y.a[2][2] = {{1, 2}, {3, 4}}

result=x+y;  // result soll {{3,4},{5,6}} ausgeben
1
class Matrix{    
2
    public:
3
        std::vector<std::vector<int>>  a;
4
        Matrix operator+(const Matrix& f_object)
5
        {
6
            Matrix result;
7
            int i = 0;
8
9
            for(int y = 0; y<a.size(); y++)
10
            {
11
                for(int z = 0; z<a[y].size(); z++)
12
                {
13
                    cout<<"a[y][z]: "<<a[y][z]<<endl;//dieser Kommentar wird noch angezeigt
14
                    result.a[y][z]=(a[y][z] + f_object.a[y][z]); // hier kommt der Absturz
15
                    cout << "f_object.a["<<y<<"]"<<"["<<i<<"]: "<< f_object.a[y][i] << endl; // dieser Kommentar nicht mehr
16
                }
17
            }
18
            return result;
19
        }
20
};

habe ich was übersehen,

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

Wie stellst Du sicher, dass a und f_object.a die selbe Dimension haben? 
Du nimmst die Größe der ersten Dimension von f_object.a und die Größe 
der zweiten Dimension von a als Iterationsgrenzen für beide Arrays. Was 
passiert, wenn die erste Dimension von a aber kleiner ist als von 
f_object.a...

von Michael S. (michaelsmith)


Lesenswert?

Andreas M. schrieb:
> Wie stellst Du sicher, dass a und f_object.a die selbe Dimension
> haben?
> Du nimmst die Größe der ersten Dimension von f_object.a und die Größe
> der zweiten Dimension von a als Iterationsgrenzen für beide Arrays. Was
> passiert, wenn die erste Dimension von a aber kleiner ist als von
> f_object.a...

hast natürlich recht, habe jetzt überall a als Referenz genommen.
die Grössen der Matrizen sind fest definiert, daher checke ich zur Zeit 
nicht ob die Grösse gleich ist.


also so funktioniert es, ich verstehe aber nicht ganz warum der 2D Array 
Ansatz nicht tut;
1
        Matrix operator+(const Matrix& f_object)
2
        {
3
            Matrix result;
4
            int i = 0;
5
6
            for(int y = 0; y<a.size(); y++)
7
            {
8
               std::vector<int> temp;
9
                for(int z = 0; z<a[y].size(); z++)
10
                {
11
                //    result.a[y][z]=(a[y][z] + f_object.a[y][z]);
12
                     temp.push_back(a[y][z] + f_object.a[y][z]);
13
                }
14
15
               result.a.push_back(temp);
16
            }
17
            return result;
18
        }

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Was soll denn passieren, wenn Du Matrizen unterschiedlicher Dimension 
addierst? Diese Frage solltest Du Dir als erstes beantworten.

Wenn Du dann zu dem Schluss kommst, dass das sinnlos ist, solltest Du 
das Du das Typsystem unterbinden.

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Wenn Du dann zu dem Schluss kommst, dass das sinnlos ist, solltest Du
> das Du das Typsystem unterbinden.

Da würde sich anbieten, "Matrix" als Template-Klasse anzulegen, mit den 
Dimensionen und dem Datentyp als Template-Parameter.

Ansonsten: auch wenn "this" und "f_objekt" beides 2×2-Matrizen sind, 
"Matrix result;" ist es nicht.

von Andreas M. (amesser)


Lesenswert?

Michael S. schrieb:
> also so funktioniert es, ich verstehe aber nicht ganz warum der 2D Array
> Ansatz nicht tut;

Weil result.a die Dimension (0,0) hat. Du musst result.a schon 
initialisieren. std::vector ist ein dynamisches array.

von Εrnst B. (ernst)


Angehängte Dateien:

Lesenswert?

Beispiel im Anhang...

von Wilhelm M. (wimalopaan)


Lesenswert?

Kleine Ergänzung:
1
#include <iostream>
2
#include <vector>
3
#include <type_traits>
4
template <size_t rows, size_t cols, typename T>
5
requires std::is_arithmetic_v<T>
6
class Matrix {
7
// ...
8
};

Denn ein
1
Matrix<42, 43, std::string>
macht ggf. wenig Sinn.

von Michael S. (michaelsmith)


Lesenswert?

ahhh, d.h. wenn ich über push_back gehe, brauche ich keine Grösenangaben 
zum Array. Wenn aber Zuweisung über die einzelnen Elemente statt findet, 
dann muss zuerst die Initialisierung her.

PS. danke fürs Template

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Denn ein
> Matrix<42, 43, std::string>
> macht ggf. wenig Sinn.

Stimmt natürlich. Würde aber Kompilieren :)
1
    Matrix<3, 3, std::string> matrixA({ {"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"} });
2
    Matrix<3, 3, std::string> matrixB({ {"9", "8", "7"}, {"6", "5", "4"}, {"3", "2", "1"} });
3
4
    Matrix<3, 3, std::string> matrixC = matrixA + matrixB;
5
6
    std::cout << "Matrix A:\n" << matrixA;
7
    std::cout << "Matrix B:\n" << matrixB;
8
    std::cout << "Matrix C (A + B):\n" << matrixC;
-->
1
Matrix A:
2
1 2 3 
3
4 5 6 
4
7 8 9 
5
Matrix B:
6
9 8 7 
7
6 5 4 
8
3 2 1 
9
Matrix C (A + B):
10
19 28 37 
11
46 55 64 
12
73 82 91

🤡

von Wilhelm M. (wimalopaan)


Lesenswert?

Und da die Matrix dann compilezeit-konstant in ihrer Größe ist, wäre 
natürlich ein std::array als Container besser.

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

Michael S. schrieb:
> PS. danke fürs Template

Hier noch eine Ergänzung für die Klasse:
1
    Matrix<cols, rows, T> transpose() const {
2
        Matrix<cols, rows, T> result;
3
4
        for (size_t i = 0; i < rows; i++) {
5
            for (size_t j = 0; j < cols; j++) {
6
                result[j][i] = data[i][j];
7
            }
8
        }
9
10
        return result;
11
    }

Für den Lern-Effekt, wie dir der Compiler mit Templates da hilft Fehler 
schon zur Compile-Zeit zu vermeiden. Für Nicht-Quadratische Matrizen 
gibt transpose einen anderen Datentyp zurück...

von Εrnst B. (ernst)


Lesenswert?

Wilhelm M. schrieb:
> Und da die Matrix dann compilezeit-konstant in ihrer Größe ist, wäre
> natürlich ein std::array als Container besser.

Psst, nicht zuviele Neuerungen auf einmal. Aber würde den Code sogar 
einfacher machen.
1
private:
2
    std::array<std::array<T, cols>, rows> data;

Und der Matrix()-Konstruktor hat dann nix mehr zu tun.

von Wilhelm M. (wimalopaan)


Lesenswert?

Man kann sogar noch etwas weiter gehen und  bspw.
1
Matrix<2, 3, float> a;
2
Matrix<2, 3, double> b;
3
4
auto c = a + b;

möglich machen. Dann ist man bei TMP und muss / sollte eine Metafunktion 
F(T1, T2) -> T schreiben, also etwa F<float, double> -> double.

von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:
> Und der Matrix()-Konstruktor hat dann nix mehr zu tun.

Falls Du den cctor meinst: nein.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Εrnst B. schrieb:
>> Und der Matrix()-Konstruktor hat dann nix mehr zu tun.
>
> Falls Du den cctor meinst: nein.

Ich weiß nicht, was das sein soll, aber er meint offenbar den 
default-Konstruktor Matrix() (wie er ja auch schreibt), der in der 
aktuellen Version dafür sorgt, dass die Vektoren ihren Speicher 
allokieren.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Εrnst B. schrieb:
>>> Und der Matrix()-Konstruktor hat dann nix mehr zu tun.
>>
>> Falls Du den cctor meinst: nein.
>
> Ich weiß nicht, was das sein soll,

die übliche Bezeichnung für copy-constructor

> aber er meint offenbar den
> default-Konstruktor Matrix() (wie er ja auch schreibt), der in der
> aktuellen Version dafür sorgt, dass die Vektoren ihren Speicher
> allokieren.

... den ich dann irgendwie übersehen hatte ...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.