Auslagerung Funktion mit struct-Kombination in eigenes .cpp-File



  • Liebe Forumspezialisten,

    derzeit habe ich den gesamten Programmcode in einem .cpp-File. Mittlerweile wird das schon etwas unübersichtlich und ich möchte diverse Funktionen auslagern. Leider habe ein Problem bei der Auslagerung einer readin-Datei in ein eigenes .cpp-File. Das Auslagern eine Zufallszahlenerzeugungs-Funktion ging ohne Probleme (mit Headerdatei und eigener .cpp Datei).

    Bei der readin-Datei übergebe ich eine komplexere Kombination aus structs (myStruct *production) an die Funktion und dabei habe ich es bis jetzt noch nicht geschafft die Dateiei „Read_Data.h“ und „Readin.cpp“ richtig zu definieren.

    Könnt ihr mir bitte anhand des unten angeführten und reduzierten Beispiels sagen, wie die externen Dateien ausgefüllt gehören, sodass ich in meiner Hauptdatei auf die extern ausgelagerte Readin-Datei korrekt zugreifen kann?

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<fstream>
    #include<string>
    #include<Windows.h>
    #include "Random_numbers.h"
    #include "Read_Data.h"
    
    using namespace std;
    
    // Struct
    struct ProdtoBlock{
    	int prodnr;
    	int blocknr;
    };
    
    struct struct_solutions{
    	vector<vector<int>> production_per_product;
    	vector<vector<int>> setup_route;
    };
    
    struct myStruct{
    	vector<vector<int>> demand;
    	…
    	…
    	…
    	vector<ProdtoBlock>prodtoblock;
    	int prodnr;
    	int blocknr;
    	struct_solutions solutions;
    	vector<struct_solutions> save_solutions;
    	vector<vector<int>> production_per_product;
    	vector<vector<int>> setup_route;
    };
    
    // Globale Variablen
    int blocki, blockj, products, macroperiods, microperiods;
    
    // Funktionen
    void readData(myStruct *production);
    
    int main(){
    
    myStruct production;
    
    readData(&production);
    
    vector<ProdtoBlock> prodtoblock;
    vector<struct_solutions> save_solutions;
    …
    calculatecost(&production);
    …
    return EXIT_SUCCESS;
    
    }
    
    void readData(myStruct * production)
    {
    	ifstream in("ABC.txt");
    	char line[1000];
    
    	if(in.fail())
    	{
    		cout << "Couldnt open ABC.txt";
    		exit(0);
    	}
    	//1. line 
    	in.getline(line, 1000);
    
    	//2. line (blocks)
    	in.getline(line, 1000, ':');
    	in >> blocki;
    	blockj = blocki;
    
    	…
    	…
    	…
    
    	//8-15. line (Demand-Matrix)
    	for (int k=0; k < products; k++)
    	{
    		vector<int> row;
    
    		for (int d=0; d < macroperiods; d++)
    		{
    			int input=1;
    			in >> input;
    			row.push_back(input);
    		}
    		(*production).demand.push_back(row);
    	}
    
    }
    

    Vielen Dank für Eure Hilfe!

    Mit freundlichen Grüßen
    PaX



  • PaX_1960 schrieb:

    Könnt ihr mir bitte anhand des unten angeführten und reduzierten Beispiels sagen, wie die externen Dateien ausgefüllt gehören, sodass ich in meiner Hauptdatei auf die extern ausgelagerte Readin-Datei korrekt zugreifen kann?

    Bitte weiter reduzieren, bis es minimal ist und noch das Problem zeigt.
    Bitte nicht soweit reduzieren, daß es nicht mehr in den Compiler passt. So … im Code bringen mir nix, die machen nur Fehlermeldungen, die nix mit der Frage zu tun haben.



  • Hallo Volkard,

    danke erstmal für deine Antwort. Ich habe das Programm jetzt noch etwas reduziert und so gestaltet, dass du es einfach copy-paste übernehmen kannst. Ich hoffe du kannst damit etwas anfangen.

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<fstream>
    #include<string>
    #include<Windows.h>
    //#include "Readin.h"
    
    using namespace std;
    
    // Struct
    struct ProdtoBlock{
    	int prodnr;
    	int blocknr;
    };
    
    struct myStruct{
    	vector<vector<int>> demand;
    	vector<ProdtoBlock>prodtoblock;
    	int prodnr;
    	int blocknr;
    };
    
    // Globale Variablen
    int products, macroperiods;
    
    // Funktionen
    void readData(myStruct *production);
    
    int main(){
    
    	myStruct production;
    
    	readData(&production);
    
    	vector<ProdtoBlock> prodtoblock;
    
    //Ausgabe
    		cout << products << " " << macroperiods <<  endl;
    
    	for(int k=0; k < products; k++)
    	{
    		for( int d=0; d < macroperiods; d++)
    		{
    			cout << production.demand.at(k).at(d) << "\t";
    		}
    		cout << endl;
    	}
    
    	getchar();
    	getchar();
    	return EXIT_SUCCESS;
    }
    
    void readData(myStruct * production){
    	ifstream in("Input.txt");
    	char line[1000];
    
    	if(in.fail())
    	{
    		cout << "Fehler beim oeffnen von Input.txt";
    		exit(0);
    	}
    	//1. Zeile Überschrift
    	in.getline(line, 1000);
    
    	//3.Zeile (Anzahl Produkte)
    	in.getline(line, 1000, ':');
    	in >> products;
    
    	//4.Zeile (Anzahl Makro-Perioden)
    	in.getline(line, 1000, ':');
    	in >> macroperiods;
    
    	//6-7. Zeile (leere Zeilen)
    	in.getline(line, 1000);
    	in.getline(line, 1000);
    	in.getline(line, 1000);
    
    	//8-15. Zeile (Demand-Matrix)
    	for (int k=0; k < products; k++)
    	{
    		vector<int> row;
    
    		for (int d=0; d < macroperiods; d++)
    		{
    			int input=1;
    			in >> input;
    			row.push_back(input);
    		}
    		(*production).demand.push_back(row);
    	}
    }
    

    Die Input.txt lautet:

    Input für das Programm
    Products: 8
    Macro-Periods: 5

    Demand
    1 1 1 1 1
    2 2 2 2 2
    3 3 3 3 3
    4 4 4 4 4
    5 5 5 5 5
    6 6 6 6 6
    7 7 7 7 7
    8 8 8 8 8

    Also die Frage lautet nun: Wie müssten die Dateien Readin.cpp und Readin.h gestaltet sein, sodass die Funktion readData ausgelagert ist.

    Vielen Dank für Eure Hilfe,

    mit freundlichen Grüßen
    PaX



  • Ich versuchs mal.

    In die Readin.cpp kommt der Code für readData und die globalen Variablen die dazu gehören.
    Dort bindest du auch nur die Header ein, die du für den Code brauchst.

    In die Readin.h kommen die Deklarationen und Definitionen, die nötig sind, damit du readData (in main ) aufrufen kannst.
    Das sind z.B. die structs und auch der Prototyp von readData
    Dort bindest du auch nur die Header ein, die nötig sind.

    Die globalen Variablen darfst du im Header nur bekannt geben. Dazu schreibst du ein extern davor.
    Das using namespace std; hat im Header auch nichts zu suchen.

    Readin.h

    #include<vector>
    
    // Struct
    struct ProdtoBlock{
        int prodnr;
        int blocknr;
    };
    
    struct myStruct{
        vector<vector<int>> demand;        // anpassen wegen std::
        vector<ProdtoBlock>prodtoblock;    // anpassen wegen std::
        int prodnr;
        int blocknr;
    };
    
    // Globale Variablen deklarieren
    extern int products, macroperiods;
    
    // Funktionen
    void readData(myStruct *production);
    

    Readin.cpp

    #include <nur das nötige>
    #include "Readin.h"
    
    using namespace std;  // muss das sein?
    
    // Struct 
    //    stehen in Readin.h
    
    // Globale Variablen definieren. Hier wird der Speicherplatz belegt
    int products, macroperiods;
    
    // Funktionen 
    // void readData(myStruct *production); das steht auch schon in Readin.h
    // Andere Funktionen, die du nur hier brauchst kannst du hier deklarieren. Die kommen nicht in den Header
    
    void readData(myStruct * production){
        dein Code hier
    }
    

    main.cpp

    #include <auch nur das nötige>
    #include "Readin.h"
    
    int main(){
    
        myStruct production;  // bekannt aus Readin.h
    
        readData(&production); // bekannt aus Readin.h
    
        ...
        return EXIT_SUCCESS;
    }
    

    Jede *.cpp Datei wird für sich alleine compiliert. Dazu muss dem Compiler alles bekannt sein, was er dafür braucht.
    Dabei werden die Dateien, die bei #include angegeben sind in den Code mit eingefügt (Textersatzt).
    Da wo vorher #include "Readin.h" stand, steht dann der ganze Inhalt von Readin.h (auch wieder mit den eingefügten includes).



  • Hallo DirkB,

    vielen Dank für deine kompetente Hilfe. Du hast das wirklich anschaulich und verständlich erklärt.

    Ich verwende das (MyStruct *production) auch noch für andere Funktionen im main-Bereich. Das heißt die Struct-Deklarationen werden von Readin.h "eingespielt" und (MyStruct *production) kann auch von anderen Funktionen verwendet werden. (So wie du es beschrieben hast)

    Durch Zufall bin ich auf eine andere Variante gekommen und wollte fragen ob das auch zulässig ist:
    Readin.cpp und Readin.h bleiben unverändert, jedoch habe ich die Struct-Deklaration im main-File zusätzlich eingefügt. Damit das ganze funktioniert darf jedoch im main-File das #include "Readin.h" NICHT inkludiert werden.

    Ist das auch eine zulässige Variante wenn ich Struct-Deklaration aus Übersichtlichkeit im main-File lassen möchte, weil eben andere Funktion auch darauf zugreifen? (Die "Deklarationen" finden beim auslagern dann halt doppelt statt...)

    Vielen Dank,

    mit freundlichen Grüßen
    PaX



  • PaX_1960 schrieb:

    Ist das auch eine zulässige Variante wenn ich Struct-Deklaration aus Übersichtlichkeit im main-File lassen möchte,

    Du baust damit eine mögliche Fehlerquelle ein, wenn du die struct änderst.
    Du brauchst dann auch noch die Prototypen aus ReadIn.h und ....

    Du schreibst den Inhalt von ReadIn.h nochmal in main.c

    Aber genau das macht das #include "ReadIn.h" schon automatisch.

    Was ist verstehst du unter mehr Übersichtlichkeit?
    Nutze deine IDE aus. die kann dir die struct-Member auch anzeigen.

    Aus Compilersicht ist das zuläassig.
    Aus Sicht der Wartbarkeit, Qualitätssicherung und Sicherheit absolut nicht.

    Durch *MyStruct production wird die Variable (Zeiger) production angelegt.
    Wo, wann und wie oft du die verwendest ist egal. Du gibst diese Variable ja an die Funktionen weiter.
    Der Compiler muss nur bei der Definition und beim Zugriff darauf wissen, wie MyStruct aufgebaut ist.
    Dies passiert mit dem #include "ReadIn.h"



  • Ursprünglich habe ich gedacht dass es übersichtlicher ist wenn die struct-Deklaration im main-File bleibt da sie von mehreren veschiedenen Funktion benötigt wird. Es erschien mir unlogisch die Deklaration einer Funktion (in diesem Fall ReadData) zuzuordnen wenn sie von anderen Funktionen auch benötigt wird...
    Aber ich finde deine Argumente durchaus einleuchtend, dass diese Mehrfachdeklaration eher eine Fehlerquelle ist, als eine Hilfe bei der Übersichtlichkeit.

    Danke jedenfalls für deine Hilfe/Tipps.

    Mit freundlichen Grüßen
    PaX



  • Die Deklaration muss auch nicht in ReadIn.h stehen, aber in main.cpp sollte sie auf gar keinen Fall.
    Du kannst auch ein myStruct.h machen, wo nur diese struct deklariert wird.
    Dies musst du dann aber in ReadIn.cpp einbinden. Und auch in ReadIn.h, da du myStruct in der Paramterliste von readData hast.

    ReadIn.cpp stellt Funktionen zur Verfügung. Alle Informationen, die der Compiler zur Nutzung dieser Funktionen braucht, kommt in ReadIn.h
    Aus ReadIn.cpp rufst du dann wiederum andere Module auf (und nutzt deren Header). Das verzweigt sich dann immer weiter nach unten.
    main steht da an oberster Stelle.


Anmelden zum Antworten