OOP: Meine KLasse geht nicht und: Wie Klassen in Dateien strukturieren?



  • Hallo, ich hoffe ich bin mit meiner Frage hier richtig.
    Da ich ja langsam so richtig in die OOP mit C++ einsteigen will, erstelle ich nun ein neues Projekt.
    Da ich bestimmten Code, also bestimmte Klassen in verschiedenen Projekten gebrauchen kann, möchte ich alle Klassen in 2 Dateien auslagern und bei Bedarf in das entsprechende Projekt includen.

    1. MeineKlasse.h, hier ist die deklaration der Klasse
    2. MeineKlasse.cpp, hier ist die definition der Klasse

    Und das eben für jede Klasse.

    Dazu habe ich einige Fragen:

    - Ist das so sinnvoll? sollte ich deklarataion und definition in eine Datei schreiben?

    - In der MeineKlasse.cpp muss ich ja div. headerfiles includieren zB. <string><stream> usw. da ich entsprechende operationen durchführe.
    Wenn ich nun 10 Klassen includiere, sind diese headerfiles im Projekt 10 mal automatisch mit-includiert. Macht das was? Schwillt der Code wahnsinnig an, weil ich 10mal dasselbe includiere? Oder ist das egal?

    - Genügt das wenn ich dann im Projekt die MeineKlasse.h includiere damit ich die Klasse benutzen kann?

    - Generell: Ist der Weg so richtig oder gibts einen Besseren?
    - Wie macht man/Ihr das?

    Soviel dazu.
    Dann habe ich noch ein anderes, bescheuertes Problemchen.
    Ich habe ja schon einige Klassen in meinem laufenden Projekt erstelle und genutzt und von daher ist die Frage etwas peinlich:

    Ich habe eine neues Projekt erstellt (VC++Express) und möchte nun gleich mit OOP anfangen.
    Dazu habe ich eine Klasse erstellt, deklariert, definiert usw..aber irgendwie gehts das nicht.
    Ich habe nun eine Testklasse erstellt:

    class CServer{
    
    public:
    
    	int test(int);
    
    };
    BOOL CServer::test(int neu){
    
    	return neu;
    
    };
    
    CServer neu;
    
    neu.test(5);
    

    Mein Problem ist nun die letzte Zeile. Da meckert der Compiler, daß "neu" unbekannt ist und er einen Default Wert "int" nicht in C++ annehmen kann.
    Aber dabei ist "neu" doch ein Instanz vom Typ CServer????????

    Was ist denn da falsch? *rotwerd*

    Danke für die Antworten Mondmann



  • Mondmann schrieb:

    Hallo, ich hoffe ich bin mit meiner Frage hier richtig.
    Da ich ja langsam so richtig in die OOP mit C++ einsteigen will, erstelle ich nun ein neues Projekt.
    Da ich bestimmten Code, also bestimmte Klassen in verschiedenen Projekten gebrauchen kann, möchte ich alle Klassen in 2 Dateien auslagern und bei Bedarf in das entsprechende Projekt includen.

    1. MeineKlasse.h, hier ist die deklaration der Klasse
    2. MeineKlasse.cpp, hier ist die definition der Klasse

    Und das eben für jede Klasse.

    Dazu habe ich einige Fragen:

    - Ist das so sinnvoll? sollte ich deklarataion und definition in eine Datei schreiben?

    besser nicht (damit ist das "in eine Datei schreiben" gemeint) - sonst bekommst du bei größeren Projekten Probleme vom Linker.

    (Ausnahme sind Template-Klassen - die MUSST du direkt im Header definieren)

    - In der MeineKlasse.cpp muss ich ja div. headerfiles includieren zB. <string><stream> usw. da ich entsprechende operationen durchführe.
    Wenn ich nun 10 Klassen includiere, sind diese headerfiles im Projekt 10 mal automatisch mit-includiert. Macht das was? Schwillt der Code wahnsinnig an, weil ich 10mal dasselbe includiere? Oder ist das egal?

    Die meisten Systemheader sind mit Include-Guards gesichert (bei deinen eigenen Headern mußt du selber dafür sorgen), da stört eine mehrfache Verwendung nicht weiter.

    - Genügt das wenn ich dann im Projekt die MeineKlasse.h includiere damit ich die Klasse benutzen kann?

    Im Prinzip ja. Eventuell muß noch der Linker passend konfiguriert werden (aber wenn du alle nötigen Klassen in deinem Projekt hast, findet der Linker sie normalerweise auch)

    - Generell: Ist der Weg so richtig oder gibts einen Besseren?
    - Wie macht man/Ihr das?

    Meistens auch so. Eventuell könnte man das noch anpassen, indem man mehrere zusammengehörige Klassen gemeinsam unterbringt.

    Dann habe ich noch ein anderes, bescheuertes Problemchen.
    ...

    CServer neu;
    
    neu.test(5);
    

    Anweisungen (und der Methodenaufruf ist eine Anweisung) kannst du nur im Inneren einer Funktion unterbringen. Auf globaler Ebene sind nur Deklarationen/Definitionen erlaubt.



  • und dann solltest dich auch auf einen returntyp festlegen, bool oder int?!



  • ser1al_ausgeloggt schrieb:

    und dann solltest dich auch auf einen returntyp festlegen, bool oder int?!

    Ja hast natürlich Recht. Aber es ging mir ums Prinzip.
    Und CStoll hat natürlich auch Recht, das geht nicht global. Das weiß ich doch normalerweise, hatte nur lauter Blumen vor den Augen vor lauter:-)

    Danke auch CStoll für Deine Informationen.Dann weiß ich daß ich auf dem richtigen Weg bin.

    Include guard wäre dann in der Header Datei:

    zB:

    #ifndef MY_HABSCHON
    #define MY_HABSCHON

    Oder?

    Grüße Mondmann



  • Mondmann schrieb:

    Include guard wäre dann in der Header Datei:

    zB:

    #ifndef MY_HABSCHON
    #define MY_HABSCHON

    Oder?

    Grüße Mondmann

    Ja, wobei du dir für jeden Header einen eigenen Namen ausdenken solltest (MEINEKLASSE_H oder ähnliche Konstrukte haben sich recht gut bewährt).



  • Alles klar.
    Vielen Dank.



  • Ok aber in der Praxis ergben sich doch so einige Fragen.

    1.
    Wenn ich zb. 10 KLassen habe, dann habe ich 10 Header und 10 CPP Dateien.
    Wenn ich in jeder Klasse zb. std::string benutze, muss ich ja in jeder der 10 Headerfiles

    #include <string>
    

    eingeben.
    Ich kann schon den Include Guard verwenden, aber nehme ich im Programm nachher alle 10 Klassen,dann ist ja <string> trotzdem 10 mal includiert, weil der Guard ja nur auf das jeweilige Headerfile wirkt.
    Oder habe ich da was falsch verstanden

    2.
    Ich möchte u.a. eine Methode schreiben die Meldungen in eine Datei schreibt.
    Dazu brauche ich

    - Den Pfad
    - Den Text
    - Einen ifstream

    und noch en paar andere Sachen.
    Den Text möchte ich als Argument übergeben, den Pfad aber nicht, sonst habe ich ja eine ellenlange Argumentenliste.
    Bisher hatte ich es so gemacht, daß der Pfad einmalig abgefragt wird und in einer globalen Variable gespeichert wird.
    Jedesmal wenn ich die Funktion dann aufrufe habe ich den Pfad parat.

    Ist jetzt ja nicht so.
    Ich meine..wie soll ich das denn machen?
    Ich muss ja dann die Klasse global Instanziieren und den Pfad zuweisen, oder?

    Generell habe ich das Problem, daß wenn ich jetzt eine Klasse "auslagern" möchte und für spätere Projekte zugänglich machen möchte, habe ich so viele Programmabhängige Variablen da drinne, daß es mit unmöglich ist diese Funktion auszulagern.
    Oder ist es doch möglich?
    Wie macht man dann sowas?

    Ein Beispiel:
    bisher eine Funktion innerhalb des Projektes:

    FKT_anmeldung()
    {
    ....
    if(art)
    ...
    else
    ...
    
    }
    

    So. Die Variable "art" ist eine globale variable. Er hat entweder 1 oder 0. Je nachdem ist zb. die Anmeldung mit Name, passwort oder nur mit der Kundennummer.

    Möchte ich das jetzt auslagern in eine KLasse und diese in anderen Projekten genau so zu nutzen, habe ich das Problem, daß die Klasse "art" in der Klassendefinition nicht kennt .
    Also muss ich "art" innerhalb der Definition anlegen:

    //Definition in der Datei "CAmeldung.cpp"
    #include "CAnmeldung.h"
    
    CAnmeldung::wie()
    {
    unsigned short art;
    
    if(art)
    ...
    else
    ...
    
    }
    

    JEtzt kennt er "art" und meckert nicht mehr.
    Da der Aufuf der Methode im Programm nachher so geht:

    CAnmeldung an;
    an.wie();
    

    Habe ich ja keinen Einfluss auf "art" da ich an die klassendefinion nicht mehr rankomme.
    KLar könnte ich "art" als Argument übergeben ( wie(art); ),aber es muss doch eine Lösung geben.
    Eine Lösung deshalb ,weil ich ne Menge Argumente habe , wenn ich 10-20 solcher Variablen drin habe.
    Dies ist bei mir oft der Fall.
    Die müsste ich dann alle übergeben....

    Ich hoffe Ihr versteht mein Problem(chen), ich denk daß es noch an meinem fehlenden Wissen liegt.

    3.
    Eine KLasse habe ich schon erfolgreich ausgelagert, allerdings brauche ich dafür keine solcher Variablen:-)

    In meinem Projekt includiere ich also die entsprechende "KLasse.h".
    Will ich nun ein Exemplar der KLasse anlegen meckert mich der Compiler an, daß er das nicht kennt.
    Ich nehme dann noch die "KLasse.cpp" in meinem Projektbaum auf und alles ist gut.
    Die Pfade kennt der Compiler.
    Muss ich das immer so machen oder gibts da einen andern Weg?

    Vielen Danke schonmal Euer unwissender Mondmann



  • @1: Da mußt du dir keine Sorgen machen - der Header <string> sollte seine eigenen Include-Guards haben und egal, wie oft und über welche Zwischenschritte er eingebunden wird, greift die Wirkung des Guards.

    @2: Du könntest der Klasse Membervariablen geben, die können dann zwischen allen ihren Methoden ausgetauscht werden:

    class CAnmeldung
    {
    public:
      melde_an();
      setze_art(int);
    private:
      int art;
    };
    
    CAnmeldung::setze_art(int a)
    {
      art = a;
    }
    
    CAnmeldung::melde_an()
    {
      switch(art)
      {...}
    }
    

    @3: Wer genau meckert? (sprich: beginnen die Fehlermeldungen mit C... (Compiler) oder LNK... (Linker)? Im letzteren Fall mußt du dem Linker noch mitgeben, wo sich die LIB zu deiner Klasse befindet (sozusagen die fertig compilierte Version der "Klasse.cpp").
    (für die in deinem Projekt enthaltenen CPP's kümmert sich die Entwicklungsumgebung darum)



  • Ok das ist natürlich ne OOP-Gute Lösung:-)
    Nur ergibt sich dann folgendes:

    Die Funktion muss ich im Programm 500 mal aufrufen weil die ja die Meldungen mitloggt.
    Der Pfad war bisher eine globale Variable.
    Ich müsste dann in jeder Funktion im Programm eine Instanz der Klasse bilden, mit der Memberfunktion den Pfad bestimmen und die Funktion aufrufen.

    Wäre da es nicht besser die Instanz global zu erstellen und auch global den Pfad reinzuschreiben?
    Oder ist das humbug?

    Die Meldung ist ein LNK Meldung, wenn ich die CPP rausnehme.
    Er meckert wegen einer unaufgelösten Funktion.

    Die ausgelagerte Klasse(n) erstelle ich alle in einem anderen Projekt.
    Auf dieses Quellverzeichnis lasse ich dann auch meinen Compiler suchen.
    JEtzt kann ich ja wegen der Lib im Compiler angeben "zusätzliche Abhängigkeiten" oder?
    (VC++ 6.0 Express)
    Ist es das oder was anderes?

    Zu allem übel erzeugt mein Projekt indem ich meine Klassen alle mache keine LIB.
    Wie bringe ich ihn dazu?

    Vielen Dank, Mondmann



  • Mondmann schrieb:

    Die Funktion muss ich im Programm 500 mal aufrufen weil die ja die Meldungen mitloggt.
    Der Pfad war bisher eine globale Variable.
    Ich müsste dann in jeder Funktion im Programm eine Instanz der Klasse bilden, mit der Memberfunktion den Pfad bestimmen und die Funktion aufrufen.

    Wäre da es nicht besser die Instanz global zu erstellen und auch global den Pfad reinzuschreiben?
    Oder ist das humbug?

    Wenn du immer die selbe Instanz benötigst, kannst du sie auch global anlegen. (der Vorteil der Klasse ist, daß du es nicht mußt - und daß du auch mehrere Logger (mit unterschiedlichen Pfaden) parallel verwenden kannst).

    Die Meldung ist ein LNK Meldung, wenn ich die CPP rausnehme.
    Er meckert wegen einer unaufgelösten Funktion.

    Die ausgelagerte Klasse(n) erstelle ich alle in einem anderen Projekt.
    Auf dieses Quellverzeichnis lasse ich dann auch meinen Compiler suchen.
    JEtzt kann ich ja wegen der Lib im Compiler angeben "zusätzliche Abhängigkeiten" oder?
    (VC++ 6.0 Express)
    Ist es das oder was anderes?

    Ja, das dürfte die richtige Position sein.

    Zu allem übel erzeugt mein Projekt indem ich meine Klassen alle mache keine LIB.
    Wie bringe ich ihn dazu?

    Frag das mal bitte drüben im MFC-Board (auch wenn ich dort als Mod eingesetzt bin, kenne ich nicht alle Eigenheiten von Visual Studio).



  • Stellt sich die Frage wie es ist wenn mehrere Instanzen des Programmes gleichzeitig auf die Dateu zugreifen?
    Wenn einer die Datei schließt und der andere was reinschreiben will?
    Ich mache die Abfrage schon,aber trotzdem kann es sein, einer schließt der andere öffnet..Schmotzt dann das Programm ab?

    Das mit de Lib habe ich hinbekommen, nur wenn ich die Einbinde bekomme ich ca. 100 Fehler das dieses und jeden Objekt schon besteht...eine Katastrophe und ich verstehs nicht warum da so ist.
    Also binde ich doch die CPP Dateien ein, dann gehts ist aber auf dauer keine Lösung...

    PS: Das board hier hat Zugriffsprobleme oder?
    Komme nur ganz selten drauf...



  • Ich glaube ich gebs auf.
    Irgendwie wird alles 5mal definiert in irgendwelchen libs.
    wenn ich dann angebe,daß ich die nicht mitlinken will, dann kommen andere Fehlermeldungen.
    Ich mache jetzt schon seit Stunden rum und es bringt nichts.
    Werde wohl OOP vergessen müssen und wie bisher weitermachen.Schade.

    Trotzdem vielen Dank für Eure geduldige Hilfe.
    grüße Mondmann



  • Ok also jetzt nochmal.
    Es muss doch eine Lösung geben,so schnell gebe ich jetzt doch nicht auf.
    Neuer tag, neues Glück.

    Ich bekomme folgende Fehlermeldung:

    Fehler	1	error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,
    class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ)
     ist bereits in Klassen.lib(CAusgabe.obj) definiert.	msvcprt.lib
    

    Da steht so nen Haufen Zeugs, daß ich nicht weiß was denn doppelt definiert ist?
    std::string????

    Die Klassen.lib ist die lib in der ich alle meine Klassen habe, die ich immer und immer wieder in verschiedenen Projekten benutzen will.

    Da habe ich natürlich <string> includiert, genau wie in meinem Projekt.
    In jedem Headerfile mit dem include Guard und trotzdem kommt die Meldung.

    Kann mir da wer helfen?
    Warum kommt diese Meldung und warum funktioniert das mit dem Guard nicht?
    Liegt es an irgendwelchen Compilereinstellungen?(VC++6.0 Express)
    Grüße Mondmann



  • Normalerweise sollte der Compiler/Linker so intelligent sein zu erkennen, daß er es hier mit Templates zu tun hat. (sprich: ich kann mir nicht erklären, warum er da einen Fehler meldet)



  • Ich habe jetzt herausgefunden , daß er die Meldung nur bringt, wenn ich eine Methode der KLasse CAusgabe aufrufe:

    1. CAusgabe output;
    2. output.Write_Client(9..);

    Erst bei (2.) kommt diese Meldung, könnte ich da was falsch gemacht haben?
    Nur was?
    Hilft Dir das viellicht weiter?


Anmelden zum Antworten