Abstrakte Klasse & Text einlesen modifizieren



  • Hallo @ all,

    habe mal ein Paar Fragen zum Thema "Abstrakte Klassen" und "Texte einlesen".

    Aufgabe: http://abload.de/img/fallcfs5m.jpg

    Materialverwaltung.h

    #pragma once
    #ifndef MATERIALVERWALTUNG_H
    #define	MATERIALVERWALTUNG_H
    #include "Material.h"
    #include <vector>
    #include <string>
    #include <sstream>
    #include <iostream>
    #include <fstream>
    
    using namespace std;
    
    class Materialverwaltung {
    public:
        Materialverwaltung();
        Materialverwaltung(const Materialverwaltung& orig);
        virtual ~Materialverwaltung();
        void materialAufnehmen(Material* mat);
        void dateiEinlesen();
        Material* findMaterial(string matNr);
    private:
        vector<Material*> materialien;
    };
    
    #endif	/* MATERIALVERWALTUNG_H */
    

    Materialverwaltung.cpp

    #include "Materialverwaltung.h"
    #include "Komponente.h"
    #include "Handelsmaterial.h"
    #include "Fertigprodukt.h"
    
    Materialverwaltung::Materialverwaltung() {
        dateiEinlesen();
    }
    
    Materialverwaltung::Materialverwaltung(const Materialverwaltung& orig) {
    }
    
    Materialverwaltung::~Materialverwaltung() {
    }
    
    void Materialverwaltung::dateiEinlesen() {
        ifstream file;
        file.open("materialien.txt", ios::in);
        if (!file) {
            cerr << "Datei konnte nicht gefunden werden!";
        }
    
        while (!file.eof()) {
    
            string buffer;
            string typ_;
            string beschreibung_;
            int bestellDauer_;
            int produktionsdauer_;
            string matNr_;
            int komponentennummer_;
            stringstream ss;
    
            //--TYP-----------------------------------------------------------------
            getline(file, buffer, '|');
            ss << buffer;
            ss >> typ_;
            ss.clear();
            //cout << typ_ << "\t";
            //--MATERIALNUMMER------------------------------------------------------
            getline(file, buffer, '|');
            ss << buffer;
            ss >> matNr_;
            ss.clear();
            //cout << materialnummer_ << "\t";
            //--MATERIALBESCHREIBUNG------------------------------------------------
            getline(file, buffer, '|');
            beschreibung_ = buffer;
            ss.clear();
            //cout << materialbeschreibung_ << "\t";
            //--BESTELLDAUER--PRODUKTIONSDAUER--------------------------------------
            if (typ_ == "H") {
                getline(file, buffer, '\r');
                ss << buffer;
                ss >> bestellDauer_;
                ss.clear();
    
                Handelsmaterial* hm(bestellDauer_, matNr_, beschreibung_);
    
                materialAufnehmen(hm);
    
                //cout << bestelldauer_ << endl;
            } else if (typ_ == "F") {
                getline(file, buffer, '\r');
                ss << buffer;
                ss >> produktionsdauer_;
                ss.clear();
                //cout << produktionsdauer_ << endl;
            } else {
                getline(file, buffer, '|');
                ss << buffer;
                ss >> bestellDauer_;
                ss.clear();
                //cout << bestelldauer_ << "\t";
            }
            //--KOMPONENTENNUMMER---------------------------------------------------
            if (typ_ == "K") {
                getline(file, buffer, '\r');
                ss << buffer;
                ss >> komponentennummer_;
                ss.clear();
                //cout << komponentennummer_ << endl;
            }
    
            Komponente* kom;
            kom->setBeschreibung(beschreibung_);
    
            materialAufnehmen(kom);
    
        }
    }
    
    void Materialverwaltung::materialAufnehmen(Material* mat) {
    
    }
    

    Material.h

    #pragma once
    #ifndef MATERIAL_H
    #define	MATERIAL_H
    #include <iostream>
    
    using namespace std;
    
    class Material {
    public:
        Material();
        Material(const Material& orig);
        virtual ~Material();
    
        virtual void setProduktionsDauer(string produktionsDauer_) = 0;
        virtual void setBestellDauer(string bestellDauer_) = 0;
    
        void setBeschreibung(string beschreibung_);
        string getBeschreibung();
        void setMatNr(string matNr_);
        string getMatNr();
    protected:
        string matNr;
        string beschreibung;
    };
    
    #endif	/* MATERIAL_H */
    

    Material.cpp

    #include "Material.h"
    
    Material::Material() {
    }
    
    Material::Material(const Material& orig) {
    }
    
    Material::~Material() {
    }
    
    void Material::setBeschreibung(string beschreibung_) {
        this->beschreibung = beschreibung_;
    }
    
    string Material::getBeschreibung() {
        return beschreibung;
    }
    
    void Material::setMatNr(string matNr_){
        this->matNr = matNr_;
    }
    
    string Material::getMatNr() {
        return matNr;
    }
    

    Komponente.h

    #ifndef KOMPONENTE_H
    #define	KOMPONENTE_H
    #include "Material.h"
    
    using namespace std;
    
    class Komponente : virtual public Material{
    public:
        Komponente(int bestellDauer_, string beschreibung_, string matNr_);
        Komponente(const Komponente& orig);
        virtual ~Komponente();
        int getBestellDauer();
    private:
        int bestellDauer;
    };
    
    #endif	/* KOMPONENTE_H */
    

    Komponente.cpp

    #include "Komponente.h"
    
    Komponente::Komponente(int bestellDauer_, string matNr_, string beschreibung_) {
        this->bestellDauer = bestellDauer_;
        setMatNr(matNr_);
        setBeschreibung(beschreibung_);
    }
    
    Komponente::Komponente(const Komponente& orig) {
    }
    
    Komponente::~Komponente() {
    }
    
    int Komponente::getBestellDauer() {
        return bestellDauer;
    }
    

    Meine Frage wäre nun einmal wie ich die Funktion dateiEinlesen() etwas kompakter gestallten kann und eine andere wäre, wieso meine "abstrakte Klasse" Material nicht funktioniert.

    Fehlermeldung von NetBeans:

    Materialverwaltung.cpp:58:69: error: expression list treated as compound expression in initializer [-fpermissive]
                 Handelsmaterial* hm(bestellDauer_, matNr_, beschreibung_);
                                                                         ^
    Materialverwaltung.cpp:58:69: error: cannot convert 'std::string {aka std::basic_string<char>}' to 'Handelsmaterial*' in initialization
    

    materialien.txt

    H|12387|HP ProBook 455 G1|10
    H|12345|Sony Vaio SVE17|14
    F|23456|Budget Star|5
    F|23457|Gaming Star|6
    F|23458|Business Star|9
    K|34567|Radeon HD 7420G Graphics|9|23456
    K|34568|AMD Dual-Core A4-4300M|8|23456
    K|34569|4 GB 1600 MHz DDR3 SDRAM|2|23456
    

    Zu beachten ist, dass beim "Typen" 'K' eine Spalte mehr existiert als bei den anderen beiden Buchstaben 'F' und 'H'.

    Danke schon mal im voraus, bisher konnte ich Dank euch einige Probleme lösen, hoffe das dieses hier auch gelöst werden kann.

    Mfg depream.



  • Weil man so

    Handelsmaterial* hm(bestellDauer_, matNr_, beschreibung_);
    

    keine Pointer auf Objekte anlegt. So wie die Aufgabe gestellt ist vermute ich, dass die materialAufnehmen Funktion den Besitz des Pointer übernimmt den man ihm gibt. Also soll man wohl vorher Speicher per new reservieren und dann an materialAufnehmen geben*. Gleiche Sache hier:

    Komponente* kom;
    kom->setBeschreibung(beschreibung_);
    

    Du hast nur einen Pointer angelegt, aber keinen Speicher reserviert.

    *Die Verwendung von new ist mittlerweile verpöhnt, da es schnell zu einem Haufen von Bugs führt und es mit Smart Pointern eine bessere Alternative gibt.



  • Ich habe es bereits mit

    Handelsmaterial* hm = new Handelsmaterial(...);
    

    erstellt, nur es will trotzdem nicht funktionieren.



  • depream schrieb:

    nur es will trotzdem nicht funktionieren.

    Heißt? Wie lautet die Fehlermeldung? Du hast auch so viel Code gepostet aber die Handelsmaterial Klasse fehlt leider.



  • Handelsmaterial* hm = new Handelsmaterial(...);
    -> ergibt folgende Fehlermeldung:

    Materialverwaltung.cpp:58:91: error: invalid new-expression of abstract class type 'Handelsmaterial'
                 Handelsmaterial* hm = new Handelsmaterial(bestellDauer_, matNr_, beschreibung_);
    

    Handelsmaterial.h

    #ifndef HANDELSMATERIAL_H
    #define	HANDELSMATERIAL_H
    #include "Material.h"
    
    class Handelsmaterial : virtual public Material{
    public:
        Handelsmaterial(int bestellDauer_, string matNr_, string beschreibung);
        Handelsmaterial(const Handelsmaterial& orig);
        virtual ~Handelsmaterial();
        int getBestellDauer();
    private:
        int bestellDauer;
    };
    
    #endif	/* HANDELSMATERIAL_H */
    

    Handelsmaterial.cpp

    #include "Handelsmaterial.h"
    
    Handelsmaterial::Handelsmaterial(int bestellDauer_, string matNr_, string beschreibung_) {
        this->bestellDauer = bestellDauer_;
        setBeschreibung(beschreibung_);
        setMatNr(matNr_);
    }
    
    Handelsmaterial::Handelsmaterial(const Handelsmaterial& orig) {
    }
    
    Handelsmaterial::~Handelsmaterial() {
    }
    
    int Handelsmaterial::getBestellDauer() {
        return bestellDauer;
    }
    


  • Die Fehlermeldung sagts ja schon: Deine Handelsmaterial Klasse ist abstrakt und daher kannst du kein Objekt davon anlegen. Die Klasse ist abstrakt wegen folgender Funktionen:

    virtual void setProduktionsDauer(string produktionsDauer_) = 0;
    virtual void setBestellDauer(string bestellDauer_) = 0;
    

    Sollten die Funktionen wirklich in die Basisklasse? Ich denke eher nicht.



  • Abstrakt ist doch die Klasse Material. Handelsmaterial erbt doch von Material. Also müsste doch Handelsmaterial durch virutal void setProduktionsDauer(..) = 0; diese Funktion erben oder verstehe ich es komplett falsch? Sinn und Zweck einer Abstrakten Klasse bzw. Vererbung ist doch, dass die Unterklassen die Public-Funktionen erbt, damit man die selben Funktionen nicht nochmal deklarieren muss?



  • Eine abstrakte Klasse ist eine Klasse mit einer oder mehreren pure virtual Funktionen (also die mit virtual funktionsname() = 0; ). Daher ist schonmal deine Material Klasse abstrakt. Aber deine Handelsmaterial Klasse ist ebenfalls abstrakt weil du die Funktionen zwar erbst aber immer noch keine Implementierung dafür hast. Sie sind also immer noch pure virtual. Die Lösung ist in Handelsmaterial die beiden Funktionen zu Implementieren (was du vermutlich nicht möchtest weil sich setProduktionsDauer gar nicht auf ein Handelsmaterial bezieht) oder die Funktionen aus der Basisklasse raus zu nehmen und nur in den entsprechenden abgeleitete Klassen zur verfügung zu stellen (möchtest du vermutlich).



  • Danke an sebi707 👍 👍 👍

    Ohh man bin ich blöd 😃 🕶

    virtual void setBeschreibung(string beschreibung_);
        virtual string getBeschreibung();
        virtual void setMatNr(string matNr_);
        virtual string getMatNr();
    

    Wieso auch immer ich die anderen Funktionen so implementiert habe, verstehe ich nun auch nicht, aber so sollte es doch richtig sein? Habe gerade auch einen Test gemacht, funktioniert so wie ich es möchte 🙂

    Aber eine Bestätigung, dass ich es richtig gemacht habe, wäre perfekt 🙂

    Ansonsten würde ich noch gerne wissen, wie ich die Funktion "dateiEinlesen()" modifizieren könnte. Ich denke es gibt bestimmt Möglichkeiten es einfacher und kürzer zu machen oder?



  • Was war jetzt die Lösung? Die 4 Funktionen da virtual zu machen wohl nicht...

    depream schrieb:

    Ansonsten würde ich noch gerne wissen, wie ich die Funktion "dateiEinlesen()" modifizieren könnte. Ich denke es gibt bestimmt Möglichkeiten es einfacher und kürzer zu machen oder?

    Ja. Was soll das ganze mit dem stringstream?

    getline(file, buffer, '|');
    ss << buffer;
    ss >> typ_;
    ss.clear();
    

    Könntest du genauso auch als

    getline(typ_, buffer, '|');
    

    schreiben. Ich vermute du hast es eingebaut um die strings zu einem int zu konvertieren. Das geht auch mit stoi.



  • Nachdem ich die 4 Funktionen auf virtual gesetzt habe, wird mir nun auch unter den Unterklassen diese Funktion angezeigt. Das sollte doch so richtig sein oder nicht?



  • Aber die Problemfälle waren doch gerade setProduktionsDauer/setBestellDauer. Was hast du mit denen gemacht?



  • Aus Material gelöscht?



  • Achso OK. Das virtual bei den 4 Funktionen wäre jetzt übrigens nicht zwingend Notwendig gewesen, da dir das nur was bringt wenn du die Funktionen in den anderen Klassen überschreiben wolltest. Ist aber sicherlich nicht verkehrt die auch virtual zu machen.

    Eine Sache die mir vorhin noch aufgefallen ist:

    class Handelsmaterial : virtual public Material{
    

    Das virtual hier braucht man nur um das Diamon Problem zu lösen. Für normale Vererbung braucht man es nicht.


Anmelden zum Antworten