Eine Instanz einer Klasse in einer anderen Klasse aufrufen



  • Hallo Leute,

    ich suche dringend eine Möglichkeit Klasseninstanzen in anderen Klassen zu verwenden.
    Ich habe gerade ein Projekt, das aus einem Client und einem Server besteht.
    Der Server allein hat zwei Klassen: Einmal für das ganze Netzwerk-Zeug (ServerNet.cpp): Der Server fährt hoch, verbindet sich, nimmt Datenanfragen des Clients entgegen und verschickt Daten.
    Die zweite Klasse enthält alle Funktionen (ServerSys.cpp): Holt sich die Daten und berechnet sie für das Verschicken um. Wenn die Berechnungen abgeschlossen sind, sollen diese an ServerNet gegeben werden, damit diese Klasse die Daten an den Client schicken kann.
    Aber eignetlich geht es nicht um den Zweck des Programms, sondern um reines C++. Ich muss eben Instanzen in anderen Klassen verwenden können.
    Da ich QT benutze ist es mir nicht möglich ServerSysin der Klasse ServerNetzu erstellen, oder andersrum. alle Instanzen müssen leider in der Main.cpp erstellt werden.

    Danke für alle Antworten!

    Main.cpp:

    #include "ServerSys.hpp"
    #include "ServerNet.hpp"
    
    int main()
    {
        ServerSys serverSys;
        ServerNet serverNet;
    }
    

    ServerNet.cpp:

    #include "ServerNet.hpp"
    #include "ServerSys.hpp"
    #include <iostream>
    
    ServerNet::ServerNet()
    {
        //Soll getData() der ServerSys-Instanz aufrufen, die in der Main-Methode erstellt wurde.
        serverSys.getData();
    }
    
    void ServerNet::sendData()
    {
        std::cout << "Daten an den Client gesendet!" << std::endl;
    }
    
    

    ServerSys.cpp:

    #include "ServerSys.hpp"
    #include "ServerNet.hpp"
    #include <iostream>
    
    void ServerSys::ServerSys() 
    {
        //Hier wird ein GUI für den Benutzer erstellt.
    }
    
    void ServerSys::getData()
    {
        std::cout << "Daten bekommen" << std::endl;
    
        //Soll sendData() der ServerNet-Instanz aufrufen, die in der Main-Methode erstellt wurde.
        serverNet.sendData();
    }
    


  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    Da ich QT benutze ist es mir nicht möglich ServerSysin der Klasse ServerNetzu erstellen, oder andersrum. alle Instanzen müssen leider in der Main.cpp erstellt werden.

    Das ist so wie es da steht falsch.



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    Da ich QT benutze ist es mir nicht möglich ServerSysin der Klasse ServerNetzu erstellen, oder andersrum. alle Instanzen müssen leider in der Main.cpp erstellt werden.

    Also das müsstest du mal näher erklären. Ich benutze auch viel QT und musste noch nie irgendwas zwangsläufig in der main.cpp machen.

    Nutzt du eigentlich das QT-Framework oder einfach nur den QTCreator als Entwicklungsumgebung? In deinem Quellcode ist jetzt von QT selber nix zu sehen.



  • @It0101

    Also wenn ich versuche ServerSys serverSys in meiner Funktion in der ServerNet Klasse zu schreiben, kommt der Fehler: QWidget: Must construct a QApplication before a QWidget. Keine Ahnung was das heißt, im Internet finde ich keine Lösung, passend zu meinem Problem dafür. Hättest du eine Lösung für diesen Fehler?
    Ich benutze das QT-Framework, allerdings habe ich den Code für die Übersichtlichkeit auf das Wesentliche reduziert, weil dieser sonst viel zu lang wäre.



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    auf das Wesentliche reduziert

    Nein du hast ihn bis zur unkenntlichkeit kastriert und dann das eigentliche Problem für dich behalten.

    Die Fehlermeldung sagt es schon: es muss zuerst ein QApplicationobject existieren, bevor GUI-Objekte instanziiert werden können. Die Riehenfolge ist entscheiden, nicht der Ort.



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    Hättest du eine Lösung für diesen Fehler?

    Wie soll man den Qt-Fehler finden ohne qt-code?
    Aber Tipp ohne code: Du hast halt wahrscheinlich irgendwo ein globales QWidget.



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    @It0101

    Also wenn ich versuche ServerSys serverSys in meiner Funktion in der ServerNet Klasse zu schreiben, kommt der Fehler: QWidget: Must construct a QApplication before a QWidget. Keine Ahnung was das heißt, im Internet finde ich keine Lösung, passend zu meinem Problem dafür. Hättest du eine Lösung für diesen Fehler?
    Ich benutze das QT-Framework, allerdings habe ich den Code für die Übersichtlichkeit auf das Wesentliche reduziert, weil dieser sonst viel zu lang wäre.

    Du willst eine QT-Anwendung bauen ( ein Frontend ? ) und hast aber keine QApplication-Instanz erzeugt, die dafür notwendig ist. Du hast also in Wirklichkeit ein ganz anderes Problem: Du hast irgendwas gemacht ohne wirklich zu wissen was du tust.

    Also meine QT-Frontends sehen alle irgendwie so oder so ähnlich aus:

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    

    Desweiteren gilt immer:
    Trennung von Datenhaltung und Visualisierung!
    D.h. deine Visualisierung ( was wohl ServerSys ist? ) sollte niemals teil der Datenhaltung ( ServerNet ) sein. Beide sind im Grunde voneinander unabjängige Objekte und sollten maximal mit einander kommunizieren, aber trotzdem räumlich getrennt. ( Kommunikation in QT: Signals und Slots ).

    Desweiteren empfiehlt es sich, den Klassen sprechende Namen zu geben. In einem Jahr weißt du doch nicht mehr ansatzweise, wofür ServerNet gut ist und wofür ServerSys gut ist.



  • Hier ist mein Code:

    Main.cpp

    #include "ServerSys.hpp"
    #include "ServerNet.hpp"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        ServerNet serverNet;
        ServerSys serverSys;
        serverSys.show();
        return a.exec();
    }
    

    ServerNet.cpp:

    #include "ServerNet.hpp"
    #include "ServerSys.hpp"
    #include <string>
    #include <iostream>
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <unistd.h>
    #include <QApplication>
    
    static QTcpSocket *socket;
    
    ServerNet::ServerNet(QObject *parent) : QObject(parent)
    {
        server = new QTcpServer(this);
        connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
        server->listen(QHostAddress::Any, 1234);
    }
    
    void ServerNet::newConnection()
    {
        socket = server->nextPendingConnection();
        receiveRequest();
    }
    
    void ServerNet::receiveRequest()
    {
        std::string receivedRequest;
        socket->waitForReadyRead(2000);
        receivedRequest = socket->readAll().toStdString();
        if(receivedRequest == "label270")
        {
            //Hier entsteht wahrscheinlich das Problem
            ServerSys serverSys;
            serverSys.sendData();
        }
        else
        {
            std::cout << "No valid data request" << std::endl;
            exit(1);
        }
    }
    
    void ServerNet::sendData(long long decLabel)
    {
        socket->write(std::to_string(decLabel).c_str());
    }
    

    ServerSys.cpp:

    #include "ServerSys.hpp"
    #include "ui_ServerSys.h"
    #include "ServerNet.hpp"
    #include <iostream>
    #include <iomanip>
    #include <sstream>
    #include <math.h>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <QDesktopWidget>
    
    ServerSys::ServerSys(QWidget *parent) : QMainWindow(parent), ui(new Ui::ServerSys)
    {
        ui->setupUi(this);
    }
    
    ServerSys::~ServerSys()
    {
        delete ui;
    }
    
    void ServerSys::sendData()
    {
        std::vector<long long> decTokens(8);
        std::vector<std::string> binTokens(8);
        std::vector<bool> binLabel;
        long long decLabel;
    
        getData(decTokens);
        calculateDecToBin(decTokens, binTokens);
        fillBinValues(binTokens);
        combineBinValues(binTokens, binLabel);
        calculateBinToDec(binLabel, decLabel);
    
        //Hier entsteht wahrscheinlich das Problem
        ServerNet serverNet;
        serverNet.sendData(decLabel);
    }
    
    void ServerSys::getData(std::vector<long long> &decTokens)
    {
        //Hier kommt nichts beim Output heraus, da ich wahrscheinlich mehrere Instanzen der Klasse ServerSys habe, obwohl 
        //ich etwas wie 12345 in das Textfeld schreibe.
        std::cout << ui->lineEdit_label_270->text().toStdString() << std::endl;
    
        decTokens[0] = ui->lineEdit_label_270->text().toLongLong();
        decTokens[1] = ui->lineEdit_sdi_270->text().toLongLong();
        decTokens[2] = ui->lineEdit_distance_270->text().toLongLong();
        decTokens[3] = ui->lineEdit_lsb_270->text().toLongLong();
        decTokens[4] = ui->lineEdit_msb_270->text().toLongLong();
        decTokens[5] = 0;
        decTokens[6] = ui->lineEdit_ssm_270->text().toLongLong();
        decTokens[7] = ui->lineEdit_parity_270->text().toLongLong();
    }
    
    void ServerSys::calculateDecToBin(std::vector<long long> &decTokens, std::vector<std::string> &binTokens)
    {
        //Berechnungen...
    }
    
    void ServerSys::fillBinValues(std::vector<std::string> &binTokens)
    {
        //Berechnungen....
    }
    
    void ServerSys::combineBinValues(std::vector<std::string> &binTokens, std::vector<bool> &binLabel)
    {
        //Berechnungen...
    }
    
    void ServerSys::calculateBinToDec(std::vector<bool> &binLabel, long long &decLabel)
    {
        //Berechnungen...
    }
    

    Also meiner Meinung nach löse ich das Problem, dass ich in ServerSys.cpp keinen Output bekomme damit, wenn ich es schaffe nur mit jeweils einer Instanz zu arbeiten. Aber ich weis leider nicht, wie ich das schaffe.



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    Also meiner Meinung nach löse ich das Problem, dass ich in ServerSys.cpp keinen Output bekomme

    Jetzt gibt es also schon wieder ein anderes Problem?



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    Also meiner Meinung nach löse ich das Problem, dass ich in ServerSys.cpp keinen Output bekomme damit, wenn ich es schaffe nur mit jeweils einer Instanz zu arbeiten. Aber ich weis leider nicht, wie ich das schaffe.

    Ich glaube, die meisten sind hier verwirrt, was eigentlich genau das Problem ist. Ich fürchte du kommst hier nicht drumherum etwas ins Detail zu gehen und genau zu sagen, was wo nicht funktioniert/kompiliert, etc.

    PS: wenn ServerSys eigentlich ein Window oder Dialog ist, dann tue dir selbst und allen Lesenden doch einfach den Gefallen und gib der Klasse einen entsprechenden Namen, einfach um Verwirrung zu vermeiden.

    Warum ist

    static QTcpSocket *socket
    

    eigentlich static?
    Der socket wird in der Klasse ServerNet verwendet um die neue Connection zu bespielen. reicht das nicht, wenn der Socket nur in der Klasse bekannt ist?
    Was passiert, wenn mehrere neue Connections reinkommen?



  • @manni66

    Nein, aber ein anderes Problem, wie ich einen richtigen Output bekomme, löst sich meiner Meinung nach damit, das Problem mit den Instanzen, wie in diesem Post beschrieben, zu lösen.
    Also das Problem bleibt bei den Instanzen. ^^



  • @It0101 @manni66

    Sorry für die Verwirrung. Werde das in meinem nächsten Post besser machen 😕
    Also das Problem, dass ich hab bleibt bei den Instanzen. Nur durch die Lösung dieses Problems lässt sich widerrum ein anderes Problem lösen, aber darum geht meine Frage auch nicht.

    Um näher ins Detail zu gehen:
    In der Main.cpp erstelle ich die Instanz von ServerNet und ServerSys. Diese müssen sich aber gegenseitig in dessen Sourcecode ansprechen. Also zum Beispiel in ServerSysmit serverNet.funktion() und in ServerNet mit serverSys.funktion().
    Ich weis allerdings nicht, wie ich diese untereinander ansprechen kann, ohne nicht eine neue Instanz zu erstellen, so wie ich es bis jetzt in ServerNet.cpp in Zeile 33, oder in ServerSys in Zeile 37 tue. Es müssen die Instanzen angesprochen werden, die in der Main.cpp erstellt wurden.



  • Interne Klassen (bzw. deren Instanzen) sollten direkt keinen Zugriff auf UI-Elemente haben.

    Auch das Anlegen der ServerNet-Variable in der mainist sinnfrei, solange du sie nicht dem UI-Element ServerSys bekanntmachst (also z.B. per Referenz als Konstruktorparameter: ServerSys(ServerNet &serverNet) und dann als Referenz-Member ablegst - oder aber sie gleich direkt als Member anlegst).

    Und in der ServerSys-Klasse greifst du dann nur auf diesen Member zu (anstatt neue ServerNet-Instanzen dort anzulegen).

    Und in der ServerNet-Instanz entkoppelst du den Zugriff auf die UI, indem du ein Signal erstellst, welches dann von der ServerSys-Instanz als Slot entgegengenommen wird (Stichwort: ereignisorientiert).



  • @Th69 sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    Interne Klassen (bzw. deren Instanzen) sollten direkt keinen Zugriff auf UI-Elemente haben.

    Auch das Anlegen der ServerNet-Variable in der mainist sinnfrei, solange du sie nicht dem UI-Element ServerSys bekanntmachst (also z.B. per Referenz als Konstruktorparameter: ServerSys(ServerNet &serverNet) und dann als Referenz-Member ablegst - oder aber sie gleich direkt als Member anlegst).

    Und in der ServerSys-Klasse greifst du dann nur auf diesen Member zu (anstatt neue ServerNet-Instanzen dort anzulegen).

    Und in der ServerNet-Instanz entkoppelst du den Zugriff auf die UI, indem du ein Signal erstellst, welches dann von der ServerSys-Instanz als Slot entgegengenommen wird (Stichwort: ereignisorientiert).

    this!

    Es ist auch kein Problem, dass ServerNet ein Member von ServerSys(Window) ist.

    ServerSys DARF ServerNet kennen. Nur andersherum nicht.
    Wenn du aus ServerNet Informationen rausholen willst:

    • Signal in ServerNet einbauen. Slot in ServerSys. Beides verbinden.
    • GetterFunktion in ServerNet einbauen, die von ServerSys aus aufgerufen wird


  • @It0101

    Ich habe es mit this in ServerNet.cpp versucht:

    void ServerNet::receiveRequest()
    {
        std::string receivedRequest;
        socket->waitForReadyRead(2000);
        receivedRequest = socket->readAll().toStdString();
        if(receivedRequest == "label270")
        {
            ServerSys serverSys;
            serverSys.sendData(this);
        }
        else
        {
            std::cout << "No valid data request" << std::endl;
            exit(1);
        }
    }
    

    Ich habe es mit einem Getter in ServerNet.cpp versucht:

    ServerNet ServerNet::getServerNet()
    {
        return *this;
    }
    

    Allerdings bekomme ich bei jedem this den Fehler:

    ServerNet.cpp:33:28: error: copying parameter of type 'ServerNet' invokes deleted constructor
    ServerNet.hpp:9:19: note: copy constructor of 'ServerNet' is implicitly deleted because base class 'QObject' has a deleted copy constructor
    qobject.h:467:20: note: 'QObject' has been explicitly marked deleted here
    

    Keine Ahnung, was ich dagegen machen kann. Weist du noch was? 😕



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    Allerdings bekomme ich bei jedem this den Fehler:

    Nein.



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    QObjects haben keinen öffentlichen Copy Constructor oder Assignment Operator. Du kannst aber einen Pointer auf das Objekt zurück geben:

    ServerNet* ServerNet::getServerNet()
    {
        return this;
    }
    


  • @Coop4Free bist du sicher, dass du dich schon an Sockets und QT-Frameworks heranwagen willst?
    Aus meiner Sicht bist du einfach noch nicht soweit.



  • @Coop4Free sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

     ServerSys serverSys;
     serverSys.sendData(this);
    

    Das ist weiterhin falsch!

    Edit: Hast du etwa
    @It0101 sagte in Eine Instanz einer Klasse in einer anderen Klasse aufrufen:

    this!

    falsch verstanden??? Damit hat @It0101 nur seine Bestätigung ausgedrückt.
    LOL



  • @It0101

    Ich habe es mit beiden von dir vorgeschlagenen Lösungen versucht, aber egal was ich versuche, ich bekomme es einfach nicht hin. Vermutlich nicht, weil deine Lösungsvorschläge falsch sind, sondern weil ich sie nur falsch umsetze und andauernd gibt es irgendwelche Fehler. 😕
    Da ich es für meine Arbeit brauche, muss ich es tun, ob ich dem Thema gewachsen bin, oder nicht.

    Könntest du mir bitte ein Codebeispiel für deine Lösungen schreiben? Das wäre sehr hilfreich.


Log in to reply