Problem mit Templates und Definitions und Implementationsdatei



  • Eldarion schrieb:

    kann man templates nur IM header implementieren? weil ich arbeite eig so, die funktionen im header zu definieren und in einer cpp datei zu implementieren. geht das net auch iwie so?

    Nein, geht bei den meisten Compilern nicht. Es sei denn es wird export für Templates unterstützt, was egtl nicht der Fall ist. Du kannst die Definition in eine extra Datei packen und in den Header inkludieren.



  • ok, danke. ich code dann mal weiter. 😃 🙂



  • hmm um deinen Codestil zu verbessern:

    #ifndef GLOG
    #define GLOG
    
    #include <fstream>
    using namespace std; // NICHT IM HEADER!
    
    class GLog
    {
        private:
            fstream Log;
        public:
            GLog();
            ~GLog();
            template<class T>
            void WriteLog(T);
            bool Open(char*); // const? std::string?
            bool Close(); // was soll den beim schließen fehlschlagen? void!
    };
    
    #endif
    

    =>

    #if !defined (G_LOG_H__INCLUDED)
    #define G_LOG_H__INCLUDED
    
    #if (_MSC_VER > 1000)
    #pragma once
    #endif // (_MSC_VER > 1000)
    
    #include <fstream>
    #include <string>
    
    namespace g // hmm lass dir nen anständigen Namen einfallen ... ;) aber hieß ja bei dir glog ...
    {
        class log
        {
        private:
            log();
            ~log();
            log& operator=(const log&);
    
        public:
            static log& instance() { static log inst; return inst; }
    
        public:
            bool open(const std::string& filename) { m_file.open(filename.c_str()); return (!m_file ? false : true); }
            void close() { m_file.close(); }
    
        public:
            template <typename T>
            bool write_data(const T& data) { if (!m_file) return false; m_file << "<p>" << data << "</p>" << std::endl; return true;}
    
        private:
            std::ofstream m_file;
        };
    };
    
    #endif // G_LOG_H__INCLUDED
    

    🙂

    #include "glog.h"
    
    int main()
    {
        g::log& log = g::log::instance(); // damit du nicht immer g::log::instance() schreiben musst ... einfach log.foo ...
        log.open("test.html");
        log.write_data("das ist eine tolle Zeile!");
    }
    

    ...



  • schonmal thx. aber dazu hab ich jetzt mal ne frage, ist es also schlechter stil definition und implemantation zu trennen?

    das G ist ja auch nur der anfangsbuchtstabe von meinem projektnamen 😉

    ich hab noch ein paar fragen dazu:

    1. kann man konstruktoren und destruktoren überhaupt private machen?

    2. was hat das hier zubedeuten? ist das eine versionsverwaltung?

    #if (_MSC_VER > 1000)
    #pragma once
    #endif // (_MSC_VER > 1000)
    

    3. warum nimmst du nicht einfach einen private teil und einen public teil?

    4. hast du die klasse grade zum singleton gemacht? so ähnlichen code hab ich schonmal bei singletons gesehn. die klasse war aber mit absicht kein singleton 😉

    das soll jetzt keine kritik sein, einfach nur ein paar verständis fragen.

    Eldarion



  • (D)Evil schrieb:

    return (!m_file ? false : true);
    

    =>

    return m_file.good();
    

    Eldarion schrieb:

    das G ist ja auch nur der anfangsbuchtstabe von meinem projektnamen 😉

    Ja, wunderbar. Benutz es als Namensbereich, so wie (D)Evil es zeigte, *nie* als Klassenpräfix.

    1. kann man konstruktoren und destruktoren überhaupt private machen?

    Sicher kann man. Dann kann die Klasse von außerhalb eben nicht mehr instanziert werden.

    2. was hat das hier zubedeuten? ist das eine versionsverwaltung?

    #if (_MSC_VER > 1000)
    #pragma once
    #endif // (_MSC_VER > 1000)
    

    Ne, '#pragma once' sorgt dafür, dass der Compiler die Datei nur einmal einbindet, macht also genau das, wofür auch Include Guards da sind. Ob es sinnvoll ist, beides zu verwenden, weiß ich nicht (ist es das?). Das '#if…' sorgt dafür, dass das Pragma nur verwendet wird, wenn der Compiler es auch versteht (mit anderen Worten: Im MS-VC++-Compiler mit Version > 1000). AFAIK verstehen aber auch jede Menge andere Compiler die '#pragma once'-Direktive.

    3. warum nimmst du nicht einfach einen private teil und einen public teil?

    Hatter doch.

    4. hast du die klasse grade zum singleton gemacht? so ähnlichen code hab ich schonmal bei singletons gesehn. die klasse war aber mit absicht kein singleton 😉

    Joar, hat er. Absichtlich. 😉



  • Hi!

    #pragma once macht nicht zu 100% das was Includeguards tun sollten (es sei denn sie werden optimiert, was auch vorkommen mag). Der Compiler merkt sich in welcher #pragma once residiert und öffnet die mein wiederinkludieren garnicht erst, d.h. man spart sich das hoch zeitaufwendige 😉 öffnen der Datei und kann so den Compilierspeed vergrößern.



  • aber dazu hab ich jetzt mal ne frage, ist es also schlechter stil definition und implemantation zu trennen?

    das wollte ich noch wissen. schonmal danke für die antworten.

    aber zu drittens: ich sehe da aber 2 private und 3 public teile.

    private:
            log();
            ~log();
            log& operator=(const log&);
       
        public:
            static log& instance() { static log inst; return inst; }
       
        public:
            bool open(const std::string& filename) { m_file.open(filename.c_str()); return (!m_file ? false : true); }
            void close() { m_file.close(); }
    
        public:
            template <typename T>
            bool write_data(const T& data) { if (!m_file) return false; m_file << "<p>" << data << "</p>" << std::endl; return true;}
    
        private:
            std::ofstream m_file;
    


  • Das is Geschmackssache.



  • Eldarion schrieb:

    aber dazu hab ich jetzt mal ne frage, ist es also schlechter stil definition und implemantation zu trennen?

    das wollte ich noch wissen. schonmal danke für die antworten.

    Na ja, generell ist es natürlich schon guter Stil. Man sollte aber aufpassen, dass man dadurch letztendlich nicht noch mehr Arbeit hat. Außerdem sind viele Bibliotheken Header-only. Das ist immer dann der Fall, wenn man (wie hier) mit Templates arbeitet. Und wenn eh alles in einer Datei ist, kann man auch gut Implementierung und Definition zusammentun, da spricht nichts gegen, wenn man es sauber schreibt.

    aber zu drittens: ich sehe da aber 2 private und 3 public teile.

    Ach so. hatte nicht bemerkt, dass die Betonung in Deiner Frage auf "einen" lag. 😉

    (D)Evil trennt hier eben verschiedene logische Bereiche der Datei, nicht privat und öffentlich sondern eben verschiedene Teile der Schnittstelle, die für sich genommen gewissermaßen Einheiten darstellen und daher beliebig angeordnet werden können. Ist gut (IMHO), weil es erlaubt, die Teile nachträglich zu verschieben, ohne dass man darauf achten muss, dass der Sichtbarkeitsbereich erhalten bleibt.



  • ok, danke für die Erklärungen zum Stil 🙂 jetzt ist mir das alles klarer geworden.



  • Eldarion schrieb:

    ...ist es also schlechter stil definition und implemantation zu trennen?...

    Nein - oft im Gegenteil.
    Bei templates ist es aber schlicht und einfach technisch nicht anders möglich (mal die "export-Exoten" mal außen vor gelassen).

    Gruß,

    Simon2.



  • Naja, gut, man kann ein ".inl" File verwenden wo man die Implementierung reinklopft. Am Ende der ".h" includiert man dann einfach das ".inl" File. Natürlich muss dann immer noch alles im public include Verzeichnis stehen, aber man hat es zumindest in 2 Files getrennt, und müllt die Definition der Klasse nicht mit lauter "Implementierung" voll.

    Mit einigen Compilern von "kurz nachm Krieg" geht es zwar nicht in jedem Fall (z.B. VC6), weil die bestimmte Konstrukte nur direkt inline verdauen. I.a. sollte es aber nix geben was man direkt in die Klasse reinimplementieren muss, auch bei templates.



  • eine kleine frage noch.
    ich hab jetzt um alle meine klassen so ein Namespace konstrukt gemacht. aber jetzt muss ich ja in den andern files ein using namespace angeben. aber wenn ich das mache, kommen einige compiler fehler das der Namespace nicht bekannt sei. Rechtschreibfehler hab ich ausgeschlossen.



  • 1. kann man Konstruktoren und Destruktoren überhaupt private machen?

    ... wie Konrad Rudolph schon richtig sagte, verhindert man somit das von außen neue Instanzen der Klasse erstellt werden können. Gehört zum Singleton dazu ...

    . hast du die klasse grade zum Singleton gemacht? so ähnlichen Code hab ich schon einmal bei Singleton's gesehen. die klasse war aber mit Absicht kein Singleton 😉

    Hmm ja habe ich. Ist bei einem Log zu 99% sinnvoll 😉 Aber wenn du einen Grund dagegen hast ... dann nimm es raus und setzt den Konstruktor public. Den copy-Operator kannst du dann raus nehmen.

    hmm der Rest wurde ja schon von den anderen erklärt ...

    ich hab jetzt um alle meine klassen so ein Namespace-Konstrukt gemacht.

    Hmm ... nicht unbedingt sinnvoll. Kommt drauf an. Wenn du bsw. eine Bibliothek geschrieben hast, bietet sich es an diese in einen Namespace zu packen. Oder auch um einzelne Teile einer Bibliothek zu trennen. Ganze Engines kannst du auch in einen Namespace schieben.


Anmelden zum Antworten