was ist an klassendefinition falsch?
-
Es geht darum, dass die Funktion
virtual void addLeft(ASTExpression e) = 0;und einige andere eine
ASTExpressionper Value übernehmen. Das heisst, diese muss kopiert werden. Das impliziert eine Konstruktion, was bei abstrakten Klassen nicht möglich ist.Also übergib
eals (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 ASTDatei 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 ASTDatei 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).
constwü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
newunddeletearbeiten. 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? Oobb
-
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() aufAber wieso hast du
newundmallocnicht? 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:-
Wo legt du die Verweise auf die Blätter ab? In car und cdr?
-
Wie und wo erzeugst du die Cellen statisch und legst diese ab? Über den Pool?
uwe
-
-
uwerothfeld schrieb:
- Wo legt du die Verweise auf die Blätter ab? In car und cdr?
- 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: 2Waehrend [/] 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 newAllerdings 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 KlasseAber 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.
-
static size_t expressionlistIndexProbier' es mit
size_t ASTExpression::expressionlistIndex = 0;in der Cpp-Datei.
-
Hi,
ah, so gehts! Fein. Jetzt habe ich nur noch nen letztes Problem. Ich bekomme in der Zeile:
return expressionList + expressionListIndex - size;folgenden Fehler:
/source/ast/astexpression.cpp:179: undefined reference to `AST::ASTExpression::expressionList'
Was mach ich den falsch (expressionlist habe ich nochmal umbenannt nach expressionList)? Noch nen Tipp??
Uwe
-
ASTExpression::expressionList ist ja ebenfalls static. Du hast es bisher nur deklariert (in der Klassendeklaration). Du brauchst auch hier noch eine Definition in der cpp.
-
Hi zum letzten ;),
nun habe ich in der .h:
//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;und in der .cpp:
//init the static counter for the simulated dynamic storage allocation size_t ASTExpression::expressionListIndex = 0; ASTExpression ASTExpression::expressionList[DSM_EXPRESSION_CNT_MAX];Ist das nicht doppeltgemommelt bzgl. der expressionList???
Uwe