was ist an klassendefinition falsch?



  • uwerothfeld schrieb:

    Die Fehlermeldungen lass ich mal weg, es sind einfach zu viele ...

    Ähm - nein! Ich bin mir fast sicher, dass in den Fehlermeldungen genau steht, wo der Fehler liegt. Zudem raten wir nicht besonders gerne.

    Rein virtuelle Methoden müssen in abgeleiteten Klassen implementiert werden, wenn diese nicht abstrakt sein sollen.



  • Hallo zusammen,

    also ich komme von Java ;). Mittels des namespace versuche ich sowas wie packages zu definieren, geht dies auch anders? Hier die gewünschten Fehlermeldungen:

    g++    -c -g -MMD -MP -MF build/Debug/GNU-Linux-x86/source/ast/astOrExpression.o.d -o build/Debug/GNU-Linux-x86/source/ast/astOrExpression.o source/ast/astOrExpression.cpp
    In file included from source/ast/astOrExpression.h:12,
                     from source/ast/astOrExpression.cpp:9:
    source/ast/astExpression.h:23: Fehler: Parameter »e« kann nicht als vom abstrakten Typ »AST::ASTExpression« deklariert werden
    source/ast/astExpression.h:16: Anmerkung:   denn die folgenden virtuellen Funktionen sind rein innerhalb »AST::ASTExpression«:
    source/ast/astExpression.h:22: Anmerkung:         virtual ExpressionType AST::ASTExpression::getType()
    source/ast/astExpression.h:23: Anmerkung:         virtual void AST::ASTExpression::addLeft(AST::ASTExpression)
    source/ast/astExpression.h:24: Anmerkung:         virtual void AST::ASTExpression::addRight(AST::ASTExpression)
    source/ast/astExpression.h:25: Anmerkung:         virtual void AST::ASTExpression::addTerm(AST::ASTExpression)
    source/ast/astExpression.h:27: Anmerkung:         virtual AST::ASTExpression AST::ASTExpression::getLeft() const
    source/ast/astExpression.h:28: Anmerkung:         virtual AST::ASTExpression AST::ASTExpression::getRight() const
    source/ast/astExpression.h:29: Anmerkung:         virtual AST::ASTExpression AST::ASTExpression::getTerm() const
    source/ast/astExpression.h:24: Fehler: Parameter »e« kann nicht als vom abstrakten Typ »AST::ASTExpression« deklariert werden
    source/ast/astExpression.h:16: Anmerkung:   denn der Typ »AST::ASTExpression« hat rein virtuelle Funktionen
    source/ast/astExpression.h:25: Fehler: Parameter »e« kann nicht als vom abstrakten Typ »AST::ASTExpression« deklariert werden
    source/ast/astExpression.h:16: Anmerkung:   denn der Typ »AST::ASTExpression« hat rein virtuelle Funktionen
    source/ast/astExpression.h:27: Fehler: ungültiger abstrakter Rückgabetyp für Elementfunktion »virtual AST::ASTExpression AST::ASTExpression::getLeft() const«
    source/ast/astExpression.h:16: Anmerkung:   denn der Typ »AST::ASTExpression« hat rein virtuelle Funktionen
    source/ast/astExpression.h:28: Fehler: ungültiger abstrakter Rückgabetyp für Elementfunktion »virtual AST::ASTExpression AST::ASTExpression::getRight() const«
    source/ast/astExpression.h:16: Anmerkung:   denn der Typ »AST::ASTExpression« hat rein virtuelle Funktionen
    source/ast/astExpression.h:29: Fehler: ungültiger abstrakter Rückgabetyp für Elementfunktion »virtual AST::ASTExpression AST::ASTExpression::getTerm() const«
    source/ast/astExpression.h:16: Anmerkung:   denn der Typ »AST::ASTExpression« hat rein virtuelle Funktionen
    In file included from source/ast/astOrExpression.cpp:9:
    source/ast/astOrExpression.h:25: Fehler: Feld »AST::ASTOrExpression::left« kann nicht als vom abstrakten Typ »AST::ASTExpression« deklariert werden
    source/ast/astExpression.h:16: Anmerkung:   denn der Typ »AST::ASTExpression« hat rein virtuelle Funktionen
    source/ast/astOrExpression.h:26: Fehler: Feld »AST::ASTOrExpression::right« kann nicht als vom abstrakten Typ »AST::ASTExpression« deklariert werden
    source/ast/astExpression.h:16: Anmerkung:   denn der Typ »AST::ASTExpression« hat rein virtuelle Funktionen
    source/ast/astOrExpression.cpp:10: Fehler: expected nested-name-specifier before »AST«
    source/ast/astOrExpression.cpp:10: Fehler: namespace »AST« in »using«-Deklaration nicht erlaubt
    source/ast/astOrExpression.cpp:12: Fehler: »ASTOrExpression« wurde nicht deklariert
    source/ast/astOrExpression.cpp:12: Fehler: ISO-C++ verbietet Deklaration von »ASTOrExpression« ohne Typ
    source/ast/astOrExpression.cpp:15: Fehler: »ASTOrExpression« is not a class or namespace
    source/ast/astOrExpression.cpp:15: Fehler: expected »,« or »...« before »&« token
    source/ast/astOrExpression.cpp:15: Fehler: ISO-C++ verbietet Deklaration von »ASTOrExpression« ohne Typ
    source/ast/astOrExpression.cpp:15: Fehler: ISO-C++ verbietet Deklaration von »ASTOrExpression« ohne Typ
    source/ast/astOrExpression.cpp:18: Fehler: expected constructor, destructor, or type conversion before »::« token
    make[2]: *** [build/Debug/GNU-Linux-x86/source/ast/astOrExpression.o] Fehler 1
    make[2]: Leaving directory `/NetBeansProjects/qep-creation'
    make[1]: *** [.build-conf] Fehler 2
    make[1]: Leaving directory `/NetBeansProjects/qep-creation'
    make: *** [.build-impl] Fehler 2
    

    Ich danke schon einmal.
    Uwe



  • Parameter »e« kann nicht als vom abstrakten Typ »AST::ASTExpression« deklariert werden

    Ist diese fehlermeldung nicht ein interessanter hinweis?
    Er versucht ein ASTExpression Objekt zu erstellen - was er natuerlich nicht kann, da ASTExpression ja abstrakt ist.

    Vergleiche dazu mal folgende 2 Funktionen und sage uns wo der unterschied zwischen foo und bar liegt...

    class C {};
    
    void foo(C c) {}
    void bar(C const& c) {}
    


  • Hi Shade Of Mine,

    ich rate mal: Rein lesender Zugriff auf ne Referenz c vom Typ C? Vielleicht noch ne Erklärung zu meiner Umgebung: Ich muß Code für einen Simulatpr entwickeln, welcher später (nach der Simulation) in einem System ohne malloc und Co ausgeführt werden soll. Daher will ich wirklich Objekte vom Typ ASTExpression in der Klasse speichern und keine Referenzen. Oder geht es irgendwie besser und ich habe nur einen Gedankenfehler???

    mfg
    uwe



  • Es geht darum, dass die Funktion

    virtual void addLeft(ASTExpression e)   = 0;
    

    und einige andere eine ASTExpression per Value übernehmen. Das heisst, diese muss kopiert werden. Das impliziert eine Konstruktion, was bei abstrakten Klassen nicht möglich ist.

    Also übergib e als (Const-)Referenz, dann wird durch Polymorphie automatisch die richtige abgeleitete Klasse ausgewählt. Diese darf dann aber nicht mehr abstrakt sein.



  • Hallo zusammen,

    erst einmal danke für die viele Hilfe. Mein Ergebnis ist nun:

    Datei astExpression.h

    namespace AST{
    
    class ASTExpression {
    public:
    
        ASTExpression() {};
        ASTExpression(const ASTExpression& orig);
        ~ASTExpression() {};
    
        virtual ExpressionType getType()                = 0;
        virtual void addLeft(const ASTExpression& e)    = 0;
        virtual void addRight(const ASTExpression& e)   = 0;
        virtual void addTerm(const ASTExpression& e)    = 0;
    
        virtual ASTExpression* getLeft() const   = 0;
        virtual ASTExpression* getRight() const  = 0;
        virtual ASTExpression* getTerm() const   = 0;
    
    private:
    
    };
    
    }//End namespace AST
    

    Datei astOrExpression.h

    #include "astExpression.h"
    
    namespace AST {
    
    class ASTOrExpression : public ASTExpression {
    
    public:
    
        ASTOrExpression();
        ASTOrExpression(const ASTOrExpression& orig);
        virtual ~ASTOrExpression();
    
        virtual ExpressionType getType()                = 0;
        virtual void addLeft(const ASTExpression& e)    = 0;
        virtual void addRight(const ASTExpression& e)   = 0;
        virtual void addTerm(const ASTExpression& e)    = 0;
    
        virtual ASTExpression* getLeft() const   = 0;
        virtual ASTExpression* getRight() const  = 0;
        virtual ASTExpression* getTerm() const   = 0;
    
    private:
    
    //    ASTExpression left;
    //    ASTExpression right;
    
    };
    
    }//End namespace AST
    

    Datei astOrExpression.cpp

    #include "astOrExpression.h"
    #include <stdlib.h>
    
    using namespace AST;
    
    ASTOrExpression::ASTOrExpression() {
    }
    
    ASTOrExpression::ASTOrExpression(const ASTOrExpression& orig) {
    }
    
    ASTOrExpression::~ASTOrExpression() {
    }
    
    ExpressionType ASTOrExpression::getType(){
        return DSM_EXPRESSION_OR;
    }
    
    void ASTOrExpression::addLeft(const ASTExpression& e){
    //    left = e;
    }
    
    void ASTOrExpression::addRight(const ASTExpression& e){
    //    right = e;
    }
    
    void ASTOrExpression::addTerm(const ASTExpression& e){
    }
    
    ASTExpression* ASTOrExpression::getLeft() const {
    //    return &left;
    }
    
    ASTExpression* ASTOrExpression::getRight() const {
    //    return &right;
    }
    
    ASTExpression* ASTOrExpression::getTerm() const  {
        return NULL;
    }
    

    So schön, so gut. Damit habe ich erst einmal keine Fehler. Nun will ich aber sagen, dass ein OrExpression halt wieder ein linken und rechten Ausdruck haben kann, vom Typ ASTExpression. Wenn ich nun aber in Datei astOrExpression die Zeilen 24,25 wieder einfüge, kommt:

    In file included from source/ast/astOrExpression.cpp:9:
    source/ast/astOrExpression.h:34: Fehler: Feld »AST::ASTOrExpression::left« kann nicht als vom abstrakten Typ »AST::ASTExpression« deklariert werden
    source/ast/astExpression.h:16: Anmerkung:   denn die folgenden virtuellen Funktionen sind rein innerhalb »AST::ASTExpression«:
    source/ast/astExpression.h:23: Anmerkung:         virtual ExpressionType AST::ASTExpression::getType()
    source/ast/astExpression.h:24: Anmerkung:         virtual void AST::ASTExpression::addLeft(const AST::ASTExpression&)
    source/ast/astExpression.h:25: Anmerkung:         virtual void AST::ASTExpression::addRight(const AST::ASTExpression&)
    source/ast/astExpression.h:26: Anmerkung:         virtual void AST::ASTExpression::addTerm(const AST::ASTExpression&)
    source/ast/astExpression.h:28: Anmerkung:         virtual AST::ASTExpression* AST::ASTExpression::getLeft() const
    source/ast/astExpression.h:29: Anmerkung:         virtual AST::ASTExpression* AST::ASTExpression::getRight() const
    source/ast/astExpression.h:30: Anmerkung:         virtual AST::ASTExpression* AST::ASTExpression::getTerm() const
    source/ast/astOrExpression.h:35: Fehler: Feld »AST::ASTOrExpression::right« kann nicht als vom abstrakten Typ »AST::ASTExpression« deklariert werden
    source/ast/astExpression.h:16: Anmerkung:   denn der Typ »AST::ASTExpression« hat rein virtuelle Funktionen
    [.....]
    Build failed. Exit value 2.
    

    Da beißt sich doch die Katze in den Schwanz. Jemand noch nen Tip? Hier ist ja const nicht anwendbar, da ich ja auf left bzw. right schon schreibend zugreifen möchte (später).

    Danke.
    Uwe



  • uwerothfeld schrieb:

    Da beißt sich doch die Katze in den Schwanz. Jemand noch nen Tip? Hier ist ja const nicht anwendbar, da ich ja auf left bzw. right schon schreibend zugreifen möchte (später).

    const würde hier auch gar nichts bringen.

    Wenn du von Java kommst, musst du in vielen Dingen umdenken. Ich würde dir raten, ein C++-Grundlagenbuch zu studieren, denn Java und C++ sind komplett verschiedene Sprachen, auch wenn sie einige Gemeinsamkeiten aufweisen. Gerade Zeiger, Speicherverwaltung, Operatorüberladung und Templates musst du auf jeden Fall neu lernen.

    Dein Problem ist eben auch ein Denkfehler, der vermutlich von Java kommt.

    ASTExpression left;
    

    Das ist eine Deklaration eines Objekts (keine Referenz wie in Java) vom Typ ASTExpression . Dieser Typ ist aber abstrakt, somit können keine Objekte davon erzeugt werden. Was du brauchst, ist ein Zeiger, der auf abgeleitete Klassen verweist.

    ASTExpression* left;
    

    Und dann mit new und delete arbeiten. Schau dir am besten wie gesagt ein Buch an, dann lernst du solche Dinge. Oft empfohlene Bücher sind der C++-Primer und Thinking in C++.



  • Hallo Nexus,

    Ok, dass habe ich verstanden. Dann werde ich mir morgen wohl mal ein Buch besorgen. Allerdings bleibt mein Problem, dass ich kein new/malloc verwenden kann (bietet das Zielsystem nicht). Kann ich in diesen Fall Polymorphie ganz abschreiben?

    Uwe



  • uwerothfeld schrieb:

    Hallo Nexus,

    Ok, dass habe ich verstanden. Dann werde ich mir morgen wohl mal ein Buch besorgen. Allerdings bleibt mein Problem, dass ich kein new/malloc verwenden kann (bietet das Zielsystem nicht). Kann ich in diesen Fall Polymorphie ganz abschreiben?

    Uwe

    ja, kannst du...
    auf was für nem system arbeitest du denn dann? Oo

    bb



  • uwerothfeld schrieb:

    Allerdings bleibt mein Problem, dass ich kein new/malloc verwenden kann (bietet das Zielsystem nicht). Kann ich in diesen Fall Polymorphie ganz abschreiben?

    Naja, du kannst "Stack-Polymorphie" anwenden, aber es ist fraglich, wie weit du damit kommst.

    Base b;         // Basisklasse
    Derived d;      // von Base abgeleitete Klasse
    
    Base* pb = &b;
    Base* pd = &d;
    
    pb->Foo();      // ruft Base::Foo() auf (Foo ist virtuell)
    pd->Foo();      // ruft Derived::Foo() auf
    

    Aber wieso hast du new und malloc nicht? Ohne kannst du ja kaum programmieren. Du kannst nichts dynamisch machen. Keine Container, keine manuelle Speicherverwaltung... Das wäre nichts für mich. 😉



  • Natürlich kannst Du auch auf solchen Systemen mit Polymorphie arbeiten, wobei ich mir kaum vorstellen kann, dass es nicht zumindest new für Objekte gibt (auch wenn die nicht auf dem Heap abgelegt werden sollten). Ansonsten kann man immernoch Standardcontainer einsetzen, um Objekte zu halten.



  • LordJaxom schrieb:

    Ansonsten kann man immernoch Standardcontainer einsetzen, um Objekte zu halten.

    Was meinst du, wie die intern arbeiten? 😛

    ohne new ist es zwar nicht vollkommen unmöglich, aber es erschwert die ganze sache natürlich ungemein - mir wären es zu viele einschränkungen, um das zu tun^^

    bb



  • Hallo zusammen,

    erst einmal danke für eure zahlreichen Kommentare. Mein Zielsystem ist ein 8 MHz MSP430 mit 10 kB RAM und 48 kB Flash. Darauf läuft eine Art Runtime, welche ein C ohne malloc und Co bietet. Mein Algorithmus soll ich aber für einen C++ basierten Simulator schreiben, wobei aber keine Elemente zur Anwendung kommen, welche auf dem Zielsystem nicht verfügbar sind. Daher der Zwangsweise verzicht auf new, malloc und Co., die einzige pseudo Dynamic, welche mir zur Verfügung steht, ist ein BufferPool, welcher eine beschränkte Anzahl von Elementen eines bestimmten Listentypes bereitstellt.

    Ist es ne gute Idee, die Expression erst zu zählen, dann lokal ein Pointerarray zu erstellen und dies dann zu verwenden für Stack based Polymorphismus?

    uwe



  • wenn du eh einen pool hast, aus dem du "fake"-dynamischen speicher bekommen kannst, dann verwende placement new oder schreib einen eigenen operator new à la

    static char dynamic_memory[1024];
    size_t counter;
    
    void* operator new (size_t s)
    {
       if (counter + s > 1024) 
         throw bad_alloc();
       else
       {
          counter += s;
          return dynamic_memory + counter - s;
       }
    }
    

    im prinzip.



  • Zielsystem ist ein 8 MHz MSP430 mit 10 kB RAM und 48 kB Flash. Darauf läuft eine Art Runtime, welche ein C ohne malloc und Co

    That's hard. Selbst arbeite ich grade an einem Scheme Interpreter fuer den embedded Bereich. C++ und Polymorphie kann ich dort aber auch nicht nutzen (so gern ich es taete). Die Allgemeine Struktur eines jeden Elements sieht etwa so aus (frei aus tinyscheme kopiert):

    /* cell structure */
    struct cell {
      unsigned int _flag;
      union {
        struct {
          char   *_svalue;
          int   _length;
        } _string;
        num _number;
        port *_port;
        foreign_func _ff;
        struct {
          struct cell *_car;
          struct cell *_cdr;
        } _cons;
      } _object;
    };
    

    Das _flag gibt den Typ an (String, Number, Symbol, Pair, ...). Daraus sind dann alle anderen Elemente wie Listen oder Baeume aufgebaut. Es ist mit automatischem memory management und man erhaelt mittels get_cell aus dem Pool von Zellen eine neue. Es ist das Aequivalent zu new. Auch muss die Runtime etwas aequivalentes wie malloc und Co. anbieten. Ansonsten muss man sich seinen eigenen memory manager fuer die 10kByte Ram schreiben.



  • Hallo zusammen,

    also die Geschichte mit dem eigenen new finde ich wirklich witzig. Da muß ich doch in der Tat mal schauen, ob ich das nicht verwenden kann. Mein Betreuer will, dass ich alles statisch definiere, was damit ja im Prinzip auch erfüllt wäre, aber dennoch einiges an Lebenserleichterung bringen würde.

    @knivil
    So ein "Monster" habe ich bis jetzt im alten C basierten Simulator verwendet. Ich hatte allerdings gehofft, die Welt ein bisschen schöner zu machen. Was ich bei deinen Ansatz aber nicht versteh sind zwei Dinge:

    1. Wo legt du die Verweise auf die Blätter ab? In car und cdr?

    2. Wie und wo erzeugst du die Cellen statisch und legst diese ab? Über den Pool?

    uwe



  • uwerothfeld schrieb:

    1. Wo legt du die Verweise auf die Blätter ab? In car und cdr?
    2. Wie und wo erzeugst du die Cellen statisch und legst diese ab? Über den Pool?

    zu 1) Jein. Scheme ist etwas anders. Z.B. ist (+ 1 2) ein Befehl zur Addition und wird in einer einfachen Liste gespeichert. car hat einen Zeiger auf eine Zelle vom Typ Symbol (+) und cdr enthaelt einen Pointer auf den Rest der Liste. (Ich empfehle dir aber eine Einfuehrung in Lisp/Scheme zu lesen, hier kann ich so schlecht Bildchen malen.) Ein Versuch:

    [car|cdr]---[car|cdr]---[car|/]
      |           |           |
      Symbol      Number      Number
       name: +     value: 1    value: 2
    

    Waehrend [/] ein Verweis auf das Nullelement ist und den Abschluss einer Liste kennzeichnet. Mit diesen rudimentaeren Konstrukten koennen alle moeglichen Expressions gebaut werden.

    zu 2) Neue Elemente werden mit z.B. cons oder mk_number konstruiert, sie Rufen get_cell auf und fordern vom Pool (beim Start initialisiert) eine freie Zelle an. Dazu Verweise ich aber erstmal auf den (haesslichen) Sourcecode von Minischeme.



  • Hallo zusammen,

    ich glaube ich habe verstanden 🙂

    uwe



  • Hallo nochmal,

    ich habe nun meine Klasse ergänzt um:

    //define a list to store all expressions
        static ASTExpression expressionList[DSM_EXPRESSION_CNT_MAX];
    
        //this index points to the next free element in the storage
        static size_t expressionlistIndex = 0;
    

    sowie

    /**
     * Overload the new operator to simulate dynamic memory allocation.
     */
    static void* ASTExpression::operator new (size_t size){
    
        if(expressionlistIndex + size > DSM_EXPRESSION_CNT_MAX){
            throw bad_alloc();
        }//End if
        else {
            expressionListIndex += size;
            return expressionList + expressionListIndex - size;
    
       }//End else
    }//End operator new
    

    Allerdings bekomme ich als Fehler:

    In file included from source/tinyDSMMain.cpp:12:
    source/ast/astexpression.h:118: Fehler: ISO-C++ verbietet Initialisierung des nicht konstanten statischen Elements »expressionlistIndex« in der Klasse
    

    Aber den Index auf den Speicher muß ich doch global initialisieren, da er ja für alle Objekte gilt. Wo ist mein Denkfehler????

    Danke nochmal.
    Uwe



  • Die Initialisierung der statischen Elemente muss außerhalb der Klasse (in der cpp) erfolgen. Genau das sagt der Compiler ja auch.


Anmelden zum Antworten