shared objects und polymorphie



  • @Mr.N
    Du scheinst hier über ein klassisches gemeines Implementationsdetail gestolpert zu sein.

    Das Problem (und seine Lösung) habe ich hier beschrieben: Wegen Konstruktor cpp-File anlegen?



  • jetzt mal alle dateien unter libcalculator.so:
    (sorry, aber ich bin verzweifelt)

    type.h:

    #ifndef TYPE_H
    #define TYPE_H
    #include <string>
    
    class type;
    
    class refcounted_ptr {
        struct internal {
            unsigned long count;
            type *p;
        } *obj;
    public:
        refcounted_ptr();
        refcounted_ptr(type *);
        refcounted_ptr(const refcounted_ptr &);
        ~refcounted_ptr();
        type *operator *() const;
        void operator=(const refcounted_ptr &);
    };
    
    class object {
        refcounted_ptr obj;
    public:
        object(type *);
        ~object();
    };
    
    class type {
    public:
        virtual ~type() = 0;
        virtual void init(void *, unsigned long = 4) = 0;
        virtual void destruct() = 0;
        virtual object convert(const std::string &) const = 0;
        virtual object convert(int) const = 0;
        virtual int tid() const = 0;
        virtual std::string tstr() const = 0;
    };
    
    typedef type *(*factory)();
    #endif
    

    environment.h:

    #ifndef ENVIRONMENT_H
    #define ENVIRONMENT_H
    #include <string>
    #include "type.h"
    
    class environment {
    public:
        environment() {}
        virtual ~environment() {}
        virtual int register_type(const std::string &, factory) = 0;
        virtual int tid(const std::string &) const = 0;
        virtual object create_object(int) const = 0;
        virtual object create_object(const std::string &) const = 0;
        virtual void *alloc(unsigned long) const;
        virtual void free(void *) const;
    };
    #endif
    

    environment_impl.h:

    #ifndef ENVIRONMENT_IMPL_H
    #define ENVIRONMENT_IMPL_H
    #include "environment.h"
    #include <map>
    #include <vector>
    
    class environment_impl : public environment {
        std::map<std::string, int> tids;
        std::vector<factory> types;
    public:
        environment_impl();
        virtual ~environment_impl();
        virtual int register_type(const std::string &, factory);
        virtual int tid(const std::string &) const;
        virtual object create_object(int) const;
        virtual object create_object(const std::string &) const;
        virtual void *alloc(unsigned long) const;
        virtual void free(void *) const;
    };
    #endif
    

    calc.h:

    #ifndef CALC_H
    #define CALC_H
    #include <string>
    class calc {
    public:
        calc();
        ~calc();
        std::string evaluate(const std::string &);
    };
    #endif
    

    calc.cpp:

    #include "calc.h"
    
    #include "environment_impl.h"
    
    //environment_impl x;
    //environment *env = &x;
    
    using namespace std;
    
    calc::calc() {
    //  env->register_type("bla", (factory) 0);
    }
    
    calc::~calc() {
    
    }
    
    string calc::evaluate(const string &s) {
        return s;
    }
    

    environment.cpp:

    #include "environment_impl.h"
    
    #include <cstdlib>
    
    using namespace std;
    
    namespace {
        unsigned long roundup(unsigned long i) {
            return i + (32768 - i % 32768);
        }
    }
    
    environment_impl::environment_impl() {
    }
    
    environment_impl::~environment_impl() {
    }
    
    int environment_impl::register_type(const string &key, factory value) {
        types.reserve(roundup(types.size() + 1));
        types.resize(types.size() + 1);
        types[types.size() - 1] = value;
        tids.insert(pair<string, int>(key, types.size() - 1));
        return types.size() - 1;
    }
    
    int environment_impl::tid(const string &key) const {
        return tids.find(key)->second;
    }
    
    object environment_impl::create_object(int i) const {
        return object((*types[i])());
    }
    
    object environment_impl::create_object(const string &key) const {
        return object((*types[tid(key)])());
    }
    
    void *environment_impl::alloc(unsigned long len) const {
        return std::malloc(len);
    }
    
    void environment_impl::free(void *p) const {
        return std::free(p);
    }
    
    //environment::~environment() {}
    

    type.cpp:

    #include "type.h"
    
    refcounted_ptr::refcounted_ptr() : obj(0) {
    }
    
    refcounted_ptr::refcounted_ptr(type *p) : obj(new internal) {
        obj->count = 1;
        obj->p = p;
    }
    
    refcounted_ptr::refcounted_ptr(const refcounted_ptr &b) : obj(b.obj) {
        ++obj->count;
    }
    
    refcounted_ptr::~refcounted_ptr() {
        if (--obj->count == 0)
            delete obj;
    }
    
    type *refcounted_ptr::operator *() const {
        return obj->p;
    }
    
    void refcounted_ptr::operator=(const refcounted_ptr &b) {
        if (--obj->count == 0)
            delete obj;
        obj = b.obj;
        ++obj->count;
    }
    
    object::object(type *p) : obj(p) {
    }
    
    object::~object() {
    }
    

    tokenizer.h und tokenizer.cpp sind ohne jeden belang (leer)



  • @HumeSikkins: und das sagst du, kurz nachdem ich den letzten post begonnen habe :D. naja, mal anschaun, was du da schreibst.



  • Hallo,
    hast du den Text gelesen? Und hast du den Destruktor von enivronment (nicht environment_impl) mal in der cpp-Datei?



  • der fehler scheint behoben *freu*. muss ich eigentlich den destruktor einer abstrakten klasse implementieren? wenn ja, WOZU?



  • muss ich eigentlich den destruktor einer abstrakten klasse implementieren?

    Ja. Ein Destruktor muss *immer* implementiert werden. Selbst wenn er pure virtual ist.

    wenn ja, WOZU?

    Auch eine abstrakte Klasse kann Datenelemente enthalten bzw. von einer Klasse mit Datenelementen erben. Und diese Datenelemte können Destruktoren besitzen. Aus diesem Grund werden auch Destruktoren von abstrakten Klassen aufgerufen, wenn Objekte von Klassen die von diesen abstrakten Klassen erben zerstört werden.
    Selbst wenn du im Dtor der abstrakten Klasse nichts tust, muss dort trotzdem zur Not Code eingebaut werden, der Basisklassen/Elementdestruktoren aufruft.



  • hmpf. ich habe aber keine daten-elemente. naja, muss wohl sein.



  • gehe ich eine gefahr ein, wenn ich diesen destruktor komplett weglasse?



  • gehe ich eine gefahr ein, wenn ich diesen destruktor komplett weglasse?

    Sicher. Implizit erzeugte Destruktoren sind nicht virtuell. Wenn du also in einer Basisklasse nicht explizit einen virtuellen Destruktor anlegst, dann hat deine Hierarchie keinen virtuellen Destruktor und jede Zerstörung eines dynamischen erzeugten Objekts einer abgeleiteten Klasse über einen Basisklassenzeiger führt zu undefiniertem Verhalten.



  • ah 🙂



  • Ach ja: Danke für die großartige Hilfe. Ohne dich säße ich wahrscheinlich noch da und hätte keine Ahnung, wo der Fehler liegt (lag).


Anmelden zum Antworten