Datenmanagement einer einfachen GUI-App



  • Hallo zusammen,

    ich habe eine App mit QT und C++ entwickelt, welche Eingabewerte über eine GUI einliest, Berechnungen durchführt und die Ergebnisse auf der UI ausgibt.

    Derzeit arbeite ich daran den Code besser zu strukturieren und in einem weiteren Schritt möchte ich, dass die Eingabewerte zusammen mit den Ergebnissen in einem Report als PDF ausgegeben werden können.

    Bislang habe ich mich per trial and error durchgekämpft und die App tut was sie soll, aber es fehlt ein sauberes Management der Daten. Daran möchte ich nun als erstem Schritt zur Implementierung des Reports arbeiten.

    Dazu nun ein paar grundsätzliche Fragen:

    Ich habe eine Klasse "DataStorage" erstellt, welche alle Parameter/Ergebnisse beinhalten soll. In welchem File erstelle ich am besten das Objekt dieser Klasse (es soll nur ein Objekt geben)?
    Der Header der Klasse sieht folgendermaßen aus (für jede Art von Berechnung soll es ein struct geben, dass die jeweils verwendeten Parameter/Ergebnisse enthält):

    #ifndef DATASTORAGE_H
    #define DATASTORAGE_H
    #include <QDebug>
    
    
    class DataStorage
    {
    
    public:
        DataStorage();
    
        void setValue(QString value);
        void getValue(double value);
    
    private:
        struct {
            double height{0};
            double d1{0};
            double d2{0};
            double asreq{0};
            double asreqComp{0};
            double fck{0};
            double span{0};
            int comboSystemCoeff{0};
            int comboNA{0};
        }flexaspectratio;
    };
    
    #endif // DATASTORAGE_H
    

    Ich schätze ich erstelle das Objekt am besten im Heap, also:

    DataStorage* StorageObj = new DataStorage();
    

    Ich habe das Objekt jetzt versuchshalber mal in der main.cpp erstellt (was vermutlich nicht der richtige Weg ist), aber wie greife ich nun von einer anderen Klasse auf die Daten zu? Wie kann ich den Pointer an andere Klassen weiterleiten?

    Ich hoffe ihr versteht einigermaßen mein Problem, ich bin leider noch ziemlich verwirrt von der OOP insbesondere im Zusammenhang mit C++.



  • @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    In welchem File erstelle ich am besten das Objekt dieser Klasse (es soll nur ein Objekt geben)?

    Dort wo Du es verwendest.

    @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Ich schätze ich erstelle das Objekt am besten im Heap, also:

    Warum?

    @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    wie greife ich nun von einer anderen Klasse auf die Daten zu?

    Parameter?

    @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Wie kann ich den Pointer an andere Klassen weiterleiten?

    Nimm eine Referenz, keinen Pointer.

    Der ganze Post macht den Eindruck als hättest Du nicht wirklich Ahnung von C++. Wenn dem so ist dann besorg Dir bitte ein Lehrbuch. Mit "trial and error" wird das nur Käse.



  • Dort wo Du es verwendest.

    Ich verwende es fast überall. Ich habe z.B. Klassen zur Berechnung der Ergebnisse und Klassen für die UI, beide müssen auf die gleichen Daten zugreifen.

    Warum?

    Ich denke aus dem Grund, dass ich es charmant finde, wenn die Daten an genau einer Stelle im Speicher liegen und ich über Pointer oder Referenz darauf zugreife. Bisher habe ich noch keine Daten im Heap verwendet (außer für die QT-Sachen), habe aber das Gefühl, dass ich vermutlich mit zig Kopien meiner eigentlichen Daten arbeite.

    Der ganze Post macht den Eindruck als hättest Du nicht wirklich Ahnung von C++. Wenn dem so ist dann besorg Dir bitte ein Lehrbuch.

    Dem ist wohl leider so. Lehrbücher habe ich schon, aber leider nicht genügend Zeit diese sorgfältig durchzuarbeiten, daher der Versuch mit learning by doing weiter zu kommen. Aber ich fürchte C++ ist dafür ein bisschen zu komplex..



  • @Engineer
    Du kannst das DataStorage an einer Stelle erzeugen, und dann den anderen Objekten die ebenfalls Zugriff darauf brauchen z.B. einfach einen Zeiger auf das DataStorage Objekt übergeben.

    Das kann im Konstruktor der anderen Objekte passieren, aber es kann auch Sinn machen es nur einzelnen Funktionen zu übergeben. Evtl. auch freien Funktionen - muss ja nicht alles immer in eine Klasse eingewickelt werden.

    z.B. könnte es gut sein dass das Erzeugen des Report-PDF eine freie Funktion ist.



  • @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Aber ich fürchte C++ ist dafür ein bisschen zu komplex..

    Dein Problem hat etwas mit Objektorientierter Modellierung zu tun und nicht mit C++.🙄



  • @Peter-Viehweger sagte in Datenmanagement einer einfachen GUI-App:

    @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Aber ich fürchte C++ ist dafür ein bisschen zu komplex..

    Dein Problem hat etwas mit Objektorientierter Modellierung zu tun und nicht mit C++.🙄

    Objektorientierter Modiellierung ist einbisschen kompliziert bei C++



  • @Estra sagte in Datenmanagement einer einfachen GUI-App:

    @Peter-Viehweger sagte in Datenmanagement einer einfachen GUI-App:

    @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Aber ich fürchte C++ ist dafür ein bisschen zu komplex..

    Dein Problem hat etwas mit Objektorientierter Modellierung zu tun und nicht mit C++.🙄

    Objektorientierter Modiellierung ist einbisschen kompliziert bei C++

    Objektorientierte Modellierung und Programmieren mit C++ haben überhaupt gar nichts miteinander zu tun!

    Also es mag sein, dass Letzeres besser funktioniert, wenn Ersteres vorher ausgeführt wurde, aber trotzdem sind das 2 völlig verschiedene Dinge.



  • @hustbaer sagte in Datenmanagement einer einfachen GUI-App:

    aber es k

    Danke für die konkrete Antwort!
    So in der Art würde ich das gerne machen. Aber mir ist noch nicht ganz klar, wie ich es bewerkstellige den Zeiger als Parameter weiterzureichen. Jede Klasse besteht ja aus separaten Dateien. Möglich wäre es eine neue Datei nur zum Zweck der Objekterstellung zu machen und diese mit #include an den Stellen einzubinden, wo ich das Objekt brauche, aber das wäre vermutlich keine saubere Architektur. Aber ich habe einfach nur Klassen für konkrete Aufgaben/Teile. Deshalb fiel mit nur die main.cpp ein um das Objekt zu erstellen. Aber main in den anderen Klassen einzubinden erscheint mir mehr als unlogisch 😅
    Ich habe da ein Henne-Ei-Problem..
    Wäre es möglich/sinvoll das Objekt direkt in der zugehörigen Datei der Klasse erstellen? Das fände ich zumindest am saubersten.
    Alternativ bin ich noch über den Singleton-Pattern gestolpert, bin aber noch nicht ganz schlau daraus geworden, ob das in meinem Fall Sinn macht.



  • @Estra

    Danke, das tut gut. Ich würde mal davon ausgehen mit einer etwas einfacheren Sprache eine steilere Lernkurve zu haben.



  • @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Aber mir ist noch nicht ganz klar, wie ich es bewerkstellige den Zeiger als Parameter weiterzureichen.

    Das lernst du hoffentlich in einem guten C++ Buch.
    Grundsätzlich bietet sich Forward Declaration an. Ist aber erstmal nur ein Begriff, es gehört schon einiges dazu, was man alles wissen/lernen sollte.



  • @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Aber ich habe einfach nur Klassen für konkrete Aufgaben/Teile. Deshalb fiel mit nur die main.cpp ein um das Objekt zu erstellen.

    Ist ja OK, dann erstell es in main().

    Aber main in den anderen Klassen einzubinden erscheint mir mehr als unlogisch

    Du musst dafür doch main() nirgends einbinden ...?

    #include "Datenobjekt.h"
    #include "AnderesObjekt.h"
    
    int main() {
        Datenobjekt daten;
        AnderesObjekt blub(&daten);
        blub.machWas();
    }
    

    Dafür braucht AnderesObjekt doch von main() nichts zu wissen...?



  • Du kannst dir die benötigten Daten auch mittels get-Methode aus dem Objekt heraus holen.



  • @hustbaer

    Danke, deine Antwort hat den Stein ins rollen gebracht. Ich hatte außer Acht gelassen, dass ich bei der Objekterstellung von Klassen Parameter mitgeben kann.

    Bei mir ist der Fall ein bisschen schwierig, weil viel QT-bezogener Code den Blick für's Wesentliche verstellt.

    #include "mainwindow.h"
    #include <QApplication>
    #include <QDesktopWidget>
    #include "DataStorage.h"
    
    
    int main(int argc, char *argv[])
    {
    
        // Making an Object for data in the heap
        DataStorage* StorageObj = new DataStorage();
    
        QApplication a(argc, argv);
        MainWindow w(nullptr, StorageObj); //passing the pointer of the data object into mainwindow
        w.show();
        return a.exec();
    }
    

    So leite ich das Datenobjekt in MainWindow und von da geht's analog weiter zu den Klassen, in welchen ich das Objekt brauche:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent, DataStorage *StorageObj)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        //Inserting the Widgets for the tabs
        ReinforcementsView* reinforcementsview = new ReinforcementsView;
        ui->gridLayoutReinforcements->addWidget(reinforcementsview);
    
        EarthPressureView* earthpressureview = new EarthPressureView(this, StorageObj);
        ui->horizontalLayoutEarthPressure->addWidget(earthpressureview);
    
        FlexuralAspectRatioView* flexuralaspecratioview = new FlexuralAspectRatioView(this, StorageObj);
        ui->verticalLayoutFlexuralAspectRatio->addWidget(flexuralaspecratioview);
    
        //add close application
        connect(ui->actionExit, &QAction::triggered,
            this, &MainWindow::close);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    Ich denke damit bin ich erstmal einen großen Schritt weiter (sofern dieser Vorgehensweise nichts entgegenspricht)!

    @Peter-Viehweger

    Genau so habe ich das vor, aber dazu brauchte ich erstmal generell Zugriff auf das Objekt.

    Vielen Dank für die zahlreichen Antworten! (auch wenn ich mir jetzt wieder ein Stück dümmer vorkomme)



  • Wenn du in Klasse A auf Methoden von Klasse B zugreifen möchtest, dann kannst du das tun, indem du einfach den entsprechenden Header von Klasse B in den Header von Klasse A einbindest.



  • @Peter-Viehweger sagte in Datenmanagement einer einfachen GUI-App:

    Wenn du in Klasse A auf Methoden von Klasse B zugreifen möchtest, dann kannst du das tun, indem du einfach den entsprechenden Header von Klasse B in den Header von Klasse A einbindest.

    Das habe ich (eigentlich) verstanden. Aber wie hilft mir das? Ich möchte ja nicht nur auf Methoden der Klasse DataStorage zugreifen sondern vor allem auf die Daten des speziellen Objekts (welches ich in main.cpp erstelle) zugreifen.



  • Meinst du sowas?

    int main()
    {
         ObjA obja;
         ObjB objb;
    
         obja.setData(objb.getData());
    
         return 0;
    }
    

    Damit holst du Daten aus objb raus und speicherst sie in obja. Also abhänging von der Implementierung und gängigen Konventionen würde getData() den Wert des (privaten) Attributs "data" zurück liefern und setData() den Wert setzen.



  • @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Ich hatte außer Acht gelassen, dass ich bei der Objekterstellung von Klassen Parameter mitgeben kann.

    😭

    Bei mir ist der Fall ein bisschen schwierig, weil viel QT-bezogener Code den Blick für's Wesentliche verstellt.

        // Making an Object for data in the heap
        DataStorage* StorageObj = new DataStorage();
    

    😭

    Bitte lass das!



  • @Engineer sagte in Datenmanagement einer einfachen GUI-App:

    Das habe ich (eigentlich) verstanden. Aber wie hilft mir das? Ich möchte ja nicht nur auf Methoden der Klasse DataStorage zugreifen sondern vor allem auf die Daten des speziellen Objekts (welches ich in main.cpp erstelle) zugreifen.

    foo.h

    #pragma once
    #include <iostream>
    
    // Bauplan:
    class foo
    {
        int data;
    
    public:
        foo(int data)
        : data{ data }
        {}
    
        void set(int new_data) { data = new_data; }
        int get() const { return data; }
    
        void bar() const { std::cout << "Hello from foo::bar()!\n"; }
    };
    

    hugo.h

    #pragma once
    #include <iostream>
    #include "foo.h"
    
    class hugo {
        foo *ptr_to_a_foo;
    
    public:
        hugo(foo *ptr_to_a_foo)
        : ptr_to_a_foo{ ptr_to_a_foo }
        {}
    
        void franz() const {
            std::cout << "Hello from hugo::franz(). The foo this hugo's pointing to contains data: "
                      << ptr_to_a_foo->get() << '\n';
            ptr_to_a_foo->bar();
        }
    };
    

    main.cpp

    #include "hugo.h"
    #include "foo.h"
    
    int main()
    {
        foo a_foo{ 42 };  // Konkrete Instanz im Speicher
        a_foo.set(36);
    
        hugo a_hugo{ &a_foo };
        a_hugo.franz();
    }
    

Log in to reply