Objektorintiert vs Harvard

Ja, oder da. :-)

Das hab ich übersehen. Ja, man braucht zumindest eine Kennung im Objekt von welcher Klasse es ist, dann findet man auch überladene Funktionen im ROM. Es gibt ein Buch (Titel vergessen, wenn du willst, such ich es raus) in dem die Internas von C++ beschrieben werden. Nein, nicht von Data Becker. Ist recht anspruchsvoll.

C++ ist _keine_ dynamische Sprache. Das wird alles zur Compile/Linkzeit aufgelöst. Ich kenne aber keine Pascal-Dialekte a la Borland, darum kann es da anders laufen (müssen).

Gruß, Nick

--
Motor Modelle // Engine Models
http://www.motor-manufaktur.de
DIY-DRO -> YADRO
Reply to
Nick Müller
Loading thread data ...

Andreas Koch schrieb:

Wie Michael bereits schrieb, so schlecht ist die Eignung nicht. Man merkt ihm außer dem Harvard-Problem auch an, dass er in 8-Bittern nicht ,zu Hause' ist (es werden mehr Operationen in 16 bits durchgezogen, als das von der Standardkonformität her zwingend nötig wäre), aber ich denke, dass dieses sogar einfacher korrigierbar wäre als das Harvard-Problem.

Anyway, ich zweifle an, dass es jemand unabhängig mit einem eigenen Compiler in weniger als 3 Jahren schafft, den GCC in irgendeiner Form hier einzuholen, erst recht nicht als Einzelperson. Das soll nicht heißen, dass es Günther nicht gelingt, einen Delphi-Compiler zu schreiben, aber bis dieser in Korrektheit und Effizienz selbst auf einem für GCC untypischen Target wie dem AVR auch nur ansatzweise brauchbar sein wird, dürfte einiges an Zeit ins Land gehen.

--
cheers, J"org               .-.-.   --... ...--   -.. .  DL8DTL

http://www.sax.de/~joerg/                        NIC: JW11-RIPE
Never trust an operating system you don't have sources for. ;-)
Reply to
Joerg Wunsch

in einem DSP thread hat Oliver mal was von einer Erfindung angedeutet, die alles "noch viel effizienter" machen wird ...

ein großes Problem ist z.B. die Latenz für Speicherzugriffe und ich könnte mir vorstellen, dass man manche Schleifen nicht unrollt sondern als unabhängige threads ausführen könnte? (schnelles switching wie im UltraSparc T1?)

oder vielleicht wenn der Compiler in Mehrprozessorsystemen irgendwie geschickt auf mehrere lokale caches verteilen will?

oder doch was ganz anderes? das neue Jahr wird spannend ... :-)

bye, Michael

Reply to
Michael Schöberl

Hehe, so soll es ja bei Erfindungen sein, man kommt eben _nicht_ sofort drauf ;-)

Drum liegt es ja auch beim Patentamt ;-)

Also gut: Wie bekannt, sind Algorithmen eigentlich immer ganz einfach, wenn da nicht fiesen Ausnahmefälle wären, und sie könnten noch einfacher sein, wenn der einfachste Fall die Regel wäre.

Nehmen wir eine Bibliothek für komplexe Zahlen, dann braucht die Multiplikation (a+i b) * (c+i d) offenbar typisch vier Multiplikations- und zwei Additionsoperationen (heutzutage ist der Trick mit drei Multiplikationen nicht mehr wirklich interessant, da mehr Additionen).

Ein typischer Fall wird nun sein, dass b oder d Null ist oder b und d. Man kann das nun teilweise mit Objektorientierung handhaben (Vererbung, abgeleitet wirklich_komplex oder real_aber_komplex_dargestellt), aber wegen der Kombination von zwei Objekten bedingt das Laufzeitabfragen und/oder gilt nur für offensichtliche Initialisierungen. Klar ist, dass der Sonderfall "Null" hier erheblich Multiplikationen spart (zwei oder gar drei).

Ein anderes Beispiel ist ein Sortieralgorithmus, bis n Elemente wird ein Bubblesort wegen geringeren Overheads schneller sein als der an sich schnelle Heap- oder Quicksort, zudem gibt es Sonderfälle mit z.B. Null Elementen, die eine ordentliche Software auch beherrschen muss.

All das kostet viel Laufzeit.

Lösung: Der Compiler erzeugt mehrere Varianten der fraglichen Routine, des Konstruktors oder wasauchimmer.

Gleichzeitig erzeugt er pro Variante einen ternären String, der die mögliche Anwendung beschreibt.

Beim Aufruf gehen die Parameter (Register oder Stack- Fenster) parallel an eine spezielle Hardware, welche auf den Registern oder dem Stack "mitlauscht" und daraus ein Eigenschaften-Bitmuster erstellt. Z.B. Bit 0 : Reg. A = 0, Bit 1: Reg. A >0, Bit 2: Reg. B = 0 usw. Weiter denkbar sind direkte Repräsentationen der untersten Bits (kleine Zahlen) usw.

Dieses Bitmuster wird um einen Aufrufcode ergänzt und geht an einen zentralen Ternär-CAM, der beim Programmstart mit den für dieses Programm möglichen Varianten-Ternärstrings geladen wurde (bei Multitasking sinnvollerweise mit einem "relozierten" Aufrufcode oder gesplitteten (Prog. Id., Call Id.) Aufrufcode). Für den allgemeinen Fall wird jeweils ein Default-Ternärstring als Rückfallebene installiert, die Reihenfolge muss natürlich wegen der Priorität eingehalten werden, die der TCAM inherent vorgibt. Standard-TCAM kann durchaus bis zu

576 Bit lange Einträge bearbeiten.

Der Ternär-CAM Speicher wertet die Eigenschaften des Aufrufs in einem Zyklus aus und gibt über ein nachgeschaltetes RAM die Einsprungadresse der für diesen Fall bestgeeigneten Routine zurück.

Beispiel Muster hier für (x;y) = (a+i b) * (c+i d) Routine mit vereinfachtem Ternärstring (a=0,b=0,c=0,d=0) (11XX) => (0;0) => Nix rechnen! (XX11) => (0;0) => dto. (X1X1) => (a*c;0) => drei Multiplikationen gespart (X1XX) => (a*c;a*d) => zwei Multiplikationen gespart (XXX1) => (a*c;b*c) => dto. (XXXX) => (a*c-b*d;a*d+b*c) => allgemeiner Fall, Rückfallebene Anmerkung: Es muss _nicht_ jeder Sonderfall eingetragen sein!

Und voila: Der Multiplikationsaufruf im o.g. Beispiel wird automatisch differenziert und kommt bei zwei Realzahlen mit einer einzigen Multiplikation aus.

Noch lustiger wird das im o.g. Beispiel, wenn die Zahlen in einem Array gespeichert sind (Vektoren), dann kann man für typische Vektordimensionen von 1 oder 2 z.B. Spezial- varianten der Routinen compilieren, die komplett die inneren for-Schleifen weglassen, jeweils wieder mit Sondervarianten für Realzahlen. Die leidigen Sprünge entfallen dann komplett.

Oder was auch interessant ist: Programm in P-Code übersetzen und zur Laufzeit eine Statistik mitführen. Wenn bestimmte Aufrufe sehr häufig vorkommen, wird der Runtime-Compiler angeworfen und baut dafür eine Sonderversion. Geht natürlich genauso für Objekte, da kann ggf. der Konstruktor bereits nach Abfrage geeignete Virtual Function Tabellen auswählen.

Woher die Infos kommen, was sich lohnt:

- Z.B.aus der Datenflußanalyse, da läßt sich durch "was wäre wenn der Parameter Null ist" sehr schnell feststellen, ob eine Optimierung was bringt und wieviel Code dann entfällt oder einfacher wird.

- Aus einer Runtime-Statistik (Profiling oder P-Code, s.o.)

- Manuell, denkbar wäre ein Statement "usably", in dem Bedingungen für eine Algorithmus-Sondervariante im Rahmen eines Overloadings angegeben werden können (hier wären die Typen zwar gleich, werden aber darüber differenziert)

- normales Overloading, Typcodes im Bitfeld.

Das Interessante ist, dass man hier mit etwas Zusatzhardware in/an der CPU und intelligentem Speicher eine komplett neue Beschleunigungsmöglichkeit "aufmacht", gerade bei der Compiler-Entwicklung sehe ich sehr viel Spielraum, wirklich gute Optimierungen zu realisieren. Außerdem ist das für P-Code a'la JAVA, C# & Co recht nett.

Gruß Oliver

P.s.: Mal schaun, wann die Erfindung in Japan oder den USA landet, hierzulande wird es vermutlich sehr schwierig, wenn wir es nicht mit eigenen Mitteln voranbringen ;-/

--
Oliver Bartels + Erding, Germany + obartels@bartels.de
http://www.bartels.de + Phone: +49-8122-9729-0 Fax: -10
Reply to
Oliver Bartels

Aha. Dann erklär doch mal das hier:

~ $cat test1.cc #include

struct base { virtual int bar(void) = 0; }; struct c1 : public base { int bar(void) { return 0; }; }; struct c2 : public base { int bar(void) { return 1; }; };

base *factory(int i) { if (i & 1) return new c1(); else return new c2(); }

int main(void) { base *x; for (int i=0; i 1

3 -> 0 4 -> 1

Das Konzept heißt Laufzeitpolymorphie. Implementiert wird es üblicherweise mit einer Tabelle (vtable) im Objekt, die die virtuellen Funktionen referenziert.

XL

Reply to
Axel Schwenke

Das hat aber nichts mit dynamischen Sprachen zu tun.

Stichwort für dynamische Sprachen ist "inspection". Damit kann man völlig unbekannte Objekte auf member-vars und member-functions untersuchen. Weiteres Kriterium ist, dass beliebige Objekte zur Laufzeit um vars und functions erweitert werden können.

Beispiele für dynamische Sprachen: Objective-C (nur teilweise) Newton-Script und sein Vorbild DYLAN.

Einen kritischen Blick auf C++ wirft James Coplien (Titel auch wieder nicht parat). In dem Buch wird klar, welcher Murx C++ bzgl. Objektorientierung ist.

Gruß, Nick

--
Motor Modelle // Engine Models
http://www.motor-manufaktur.de
DIY-DRO -> YADRO
Reply to
Nick Müller

Axel Schwenke schrieb:

Soweit ich das um die Uhrzeit noch überblicke wird aber doch die vtable zur Compilezeit aufgebaut und eh' immer bis zum Ende durchgenudelt, eh dann endlich gesprungen wird.

Markus

Reply to
Markus Becker

Du hast drei feste Klassen die alle zu base kompatibel sind. Damit reicht es, bei jeder Instanz einfach einen Pointer auf den aktuell verwendeten Klassentyp zu speichern - du kannst aber nicht zur Laufzeit z.B. in eine Klasse noch einen Int reinbauen, du kannst nur eine bereits vorhandene Klasse verwenden die bereits einen zusätzlichen Int enthält.

Reply to
Andreas Koch

Also ich kenne das was du beschreibst als "Reflection".

Java nicht vergessen. In D ist das glaubich auch geplant. Und für C++ gibt es IMHO auch Libaries, die Reflection ermöglichen:

formatting link

Naja, ich finde C++ funktioniert recht gut. Obwohl mir D noch um einiges besser gefällt, ist für OOP im Moment C++ keine schlechte Wahl. Trotzdem fänd ich es gut, wenn du den Titel herauskramen könntest, mich würde die Kritik wirklich interessieren.

Viele Grüße, Johannes

Reply to
Johannes Bauer

Das Stichwort hast ja auch du ins Spiel gebracht, obwohl es eigentlich nur um C++ ging. Mir ging es darum, deine flashce Aussage "Das wird alles zur Compile/Linkzeit aufgelöst." zu widerlegen. Aufrufe virtuelle Methoden werden nämlich erst zur Laufzeit aufgelöst. Zwar für alle Objekte einer Klasse gleich, aber auch das war kein Diskussionspunkt.

Danke, ich kenne den Unterschied.

Es gibt *immer* eine Sprache, die irgendwas besser macht. Für das, was ich damit mache (zugegebenermaßen nicht viel) hat C++ immer ausgereicht. Wenn es um OO geht, finde ich Ruby sehr nett. Das ist wohl sehr Smalltalk-isch.

Was viele C++-Gegner immer wieder vergessen ist, daß ein Designziel bei C++ die weitgehende Kompatibilität zu C war. Viele "Schwächen" von C++ haben hier ihren Ursprung.

XL

Reply to
Axel Schwenke

Ich weiß nicht, was du mit "durchgenudelt" meinst. Aber ja, die vtable wird zur Compilezeit aufgebaut (die Implementierung virtueller Funktionen ist beim Compilieren abgeschlossen).

Insofern kann die vtable auch im ROM liegen und das Objekt ent- hält nur einen Pointer auf "seine" vtable. Sehr wahrscheinlich wird das in der Praxis genau so gemacht.

XL

Reply to
Axel Schwenke

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Diesen Satz habe ich wohl zu Unrecht gequotet.

Den dann nicht mehr.

Kein Widerspruch.

Wobei mir jetzt spontan nix einfällt, wozu ich das brauchen wollten könnte.

XL

Reply to
Axel Schwenke

Sieh es so: Die Schwächen von C++ sind auch seine Stärken: => Es läßt sich per Preprozessor problemlos nach C übersetzen => C eignet sich hervorragend für Embedded Systeme, da will man die "Dynamik" a'la Smalltalk nicht wirklich.

Meldungen wie "finde keine passende Methode zum Landen" sind in einem Flugzeugcontroller nicht gerade der Hit ;-/

Überraschungen sind bei Embedded nicht nur nicht, sondern garnicht erwünscht, und man möchte auch keinen großen Interpreter zur Laufzeit (Java), der Rechenzeit wie Speicher- Resourcen frisst. Von daher gilt für diese Anwendungen:

- Je mehr statisch und vorab gerechnet und validiert wird, umso besser.

Und in irgendeiner Sprache darf schließlich auch der Interpreter bzw. der Betriebssystem-Kern geschrieben sein ...

Gruß Oliver

--
Oliver Bartels + Erding, Germany + obartels@bartels.de
http://www.bartels.de + Phone: +49-8122-9729-0 Fax: -10
Reply to
Oliver Bartels

Axel Schwenke schrieb:

Ich meinte, daß mein Aufruf einer Methode durch einen Zeiger auf die Basisklasse immer die Methode der "am weitesten" abgeleitete Klasse aufgerufen wird. Weitere Nachforschungen meinerseits, bzw. der Versuch, kompilierbaren Beispielcode zu erstellen ergaben aber das Gegenteil. Bei weiterem Nach- denken war das ja auch irgendwie Quatsch. Evtl. sollte ich um solche Uhrzeiten wirklich nicht mehr posten.

Beispielcode (anders formatiert, als ich das sonst mache, damit man es auf eine Seite kriegt):

#v+ // ---------------- %< -------------------------------- #include

class base { public: virtual void nudel()=0; };

class abg1:base { public: virtual void nudel(); };

class abg2:abg1 { public: virtual void nudel(); };

void abg1::nudel() { std::cout nudel(); // soll sich doch das BS um's delete kümmern ... return 0; } // ---------------- %< -------------------------------- #v-

ergibt folgende Ausgabe:

markus@beta-cygni ~/News $ ./a.out

  1. Ableitung
  2. Ableitung
  3. Ableitung
  4. Ableitung
  5. Ableitung
  6. Ableitung

Wieder was gelernt.

Markus

Reply to
Markus Becker

ACK

Ja? Es ging darum, ob man den code für Objekte im ROM unterbringt. Ich sagte, dass es bei nicht-dynamischen Sprachen geht. ...

Und, ist es dir gelungen? Versuch doch mal eine beliebige Klasse ("class void"?) an eine Funktion zu übergeben. Es geht nicht, dem Compiler sind und müssen alle Klassen komplett bekannt sein, sonst kann er den Code nicht generieren.

Ja, klar, darum ging es auch nicht. Oder doch? Mir ist wohl mein Hass auf C++ etwas ausser Kontrolle geraten.

ACK In einem uC hat mMn C++ nichts verloren. Sondern C. Man kann mit C leicht Klassen nachbilden, es gehört nur Disziplin dazu.

Gruß, Nick

--
Motor Modelle // Engine Models
http://www.motor-manufaktur.de
DIY-DRO -> YADRO
Reply to
Nick Müller

Nach meinem Verständnis sagtest du noch mehr.

Ich denke schon. "alles wird zur Compile/Linktime aufgelöst" ist eine andere Aussage als "jeglicher Programmcode wird zur Compile/ Linktime generiert"

Vermutlich haben wir uns also nur um leere Worte gestritten. Du solltest weiter üben, das was du meinst, auch zu sagen ;-)

Ax "ob das Spätfolgen des Mathe-Studiums sind?" el

Reply to
Axel Schwenke

Ja, da hast Du recht. Also: Der complette Code wird zur compile/link-Zeit generiert. Der Code (incl. Klassenmethoden) kann im ROM stehen. Alle Objekte die übergeben werden können sind zur compile-Zeit wohl bekannt. (Was bedeutet, dass es einfach kracht wenn ein -durch einen bösen cast- übergebenes Objekt nicht dem entspricht, was der Compiler gesagt bekam). Zur Laufzeit wird (oder muss) nicht an den Objekten ruminterpretiert.

Gruß, Nick

--
Motor Modelle // Engine Models
http://www.motor-manufaktur.de
DIY-DRO -> YADRO
Reply to
Nick Müller

Was heißt "eine beliebige Klasse übergeben"? Ein Objekt beliebigen Typs? 'void*' existiert. Ein Handle auf eine Klasse, damit man z.B. neue Instanzen anlegen kann (das, was 'Class' in Java ist)? Kann man bei Bedarf in Nullkommanix selber bauen. struct Class { virtual void* clone(void*) = 0; virtual void* construct() = 0; }; template struct ConcreteClass : Class { void* clone(void* p) { return new T(*static_cast(p)); } void* construct() { return new T(); } };

void makeTenInstances(const Class& c) { for (int i = 0; i < 10; ++i) c.construct(); } // ... makeTenInstances(ConcreteClass()); Vorteil: wenn du's nicht brauchst, musst du's nicht mit dir rumschleppen.

Du kannst nicht zur Laufzeit Klassen manipulieren. "Mal eben jedem existierenden String-Objekt noch einen int einfügen" geht sowieso eher selten ohne komplettes Reallokieren aller dieser Objekte.

Warum soll man in C Klassen nachbilden, wenn man in C++ gleich Klassen hinschreiben kann? Der Code, der hinten rausfällt, ist in einem ordentlich konfigurierten Compiler der gleiche.

Eventuell sogar besserer, da z.B. std::sort eben den Vergleich direkt codieren kann, wo qsort einen Funktionszeiger aufrufen muss. Oder da inline-Funktionen in C++ schon länger Standard sind als in C.

Zugegebenermaßen ist es in C++ einfacher, versehentlich Bloat zu produzieren.

Stefan

Reply to
Stefan Reuther

Soweit ACK.

Jein. Bis auf virtuelle Methoden. Zur Compilezeit ist zwar bekannt, welches Interface das Objekt besitzt (vulgo: welche virtuellen Methoden mit welchen Signaturen es kennt). Es ist aber nicht bekannt, welche Implementierung zur Laufzeit gewählt wird. Exakt das sollte mein Beispiel verdeutlichen. Notfalls stell dir einfach vor, i käme aus einer Nutzereingabe.

XL

Reply to
Axel Schwenke

Ich glaube wir reden hier wirklich alle aneinander vorbei :-)

Obiges ist für mich kein Wiederspruch.

Die Objekt(-Typen) sind zur Compile-Zeit wohl bekannt ->

Es ist bekannt daß es ein base, c1 und c2 gibt, und was sie machen.

Die Variablen(-Inhalte) sind zur Compile-Zeit nur begrent bekannt->

Ein Pointer auf Base kann auch Nachfolger von base enthalten.

Reply to
Andreas Koch

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.