Virtual sinnhaft?
-
JimmydaMage schrieb:
Nicht-Virtuelle Methoden zu verwenden macht IMHO dann Sinn, wenn der Speicher sehr begrenzt ist, da jede virtuelle Methode einen Zeiger in der Funktionstabelle benötigt. Das mag bei PCs mit Speicher im GB Bereich egal sein, bei einem Microcontroller mit 1 oder 2KB RAM, sollte man schon dreimal überlegen, ob man hier
die virtuelle Methode wirklich benötigt. Und da Portabilität nun mal einer der Hauptaspekte bei der Entwicklung von C/C++ war, ermöglicht die Sprache eben, selbst zu entscheiden, welche Methoden virtuell sein sollten...Der Speicher ist nahezu uninteressant, selbst bei begrenzten Systemen. Die VTable ist 4 Byte + (4 Byte * Anzahl virtueller Funktionen) groß, also auch bei sehr flexiblen Objekten überschaubar.
Wichtig ist, dass sich (unnötige) virtuelle Funktionen nicht in (geschachtelten) Schleifen finden. Hier kann alleine ein einfacher Zugriff (Stack->Object->Element) einen Algorithmus stark beschleunigen, wenn man vor der Schleife "temp = Object->Element" setzt und so eine Addition und Dereferenzierung spart: Stack->temp.
Bei einer virtuellen Funktion lautet der Zugriff Stack->Objekt->VTable->Funktion( Stack->Objekt ) statt static_func( Stack->Object );Die Berücksichtigung dieser Sachlage machte bei einer Optimierung, die ich vor ein paar Monaten machte, bedeutete einen Laufzeitunterschied von ursprünglich 60s auf 25s. Dereferenzierungen sind nicht teuer, können sich aber in Algorithmen, die große Datenmengen verarbeiten, teuer aufaddieren.
Computer sind heutzutage schneller als früher, aber das hilft nur bedingt, viele Programmierer argumentieren damit, dass man deswegen nicht mehr so aufmerksam programmieren muss.
Ein Prof von mir formulierte das provokanter: "Programmierer werden noch schneller dumm, als Computer schneller."
-
Xin schrieb:
Ein Prof von mir formulierte das provokanter: "Programmierer werden noch schneller dumm, als Computer schneller."
dumm nicht, eher faul und bequem. ob das jetzt gut oder schlecht ist, ist eine andere frage.

-
Xin schrieb:
wiwie schrieb:
Hallo otze,
ja so meinte ich das auch nicht. Mir war bewusst, dass Subklassen die Methoden der Basisklasse überschreiben können.Mir ist nur nicht klar, weshalb das Schlüsselwort virtual überhaupt benötigt wird. Es kann ja nicht darum gehen, dem Compiler mitzuteilen, dass die Methode in den Subklassen existiert, denn das tut sie ja auf jeden Fall.
Aber woher soll der Compiler wissen, dass es überhaupt Subklassen gibt?
Warum sollte er es nicht wissen? Es gibt doch in C++ garnicht die Möglichkeit Klassen zur Laufzeit zu laden. Also weiß doch der Compiler ob es Subklassen gibt und ob diese eine Methode überschreiben. Wieso kann der Compiler dann das setzen von virtual nicht automatisch machen?
-
In vielen Fällen weiß es nicht der Compiler, sondern frühestens der Linker. Und solange der ein C-Linker bleibt, hat er keinen Eingriff in den Compiliervorgang.
Und außerdem gibts DLLs, mit denen sowas wie "Klassen zur Laufzeit laden" praktikabel ist

-
Auf jeden Fall kann er nicht wissen, auf welches Objekt ein Pointer zur Laufzeit zeigt.
Und je nachdem, ob der Pointer auf ein Objekt die Basisklasse oder der abgeleiteten Klasse ist, muss die entsprechende Funktion ausgewählt werden - das ist ja der Sinn von virtual ;)./Edit:
Was ist eigentlich hier genau mit "Klassen zu Laufzeit laden" gemeint?
-
Was ist eigentlich hier genau mit "Klassen zu Laufzeit laden" gemeint?
Eine Instanz per 'new' auf dem Heap anlegen.
-
mikey schrieb:
Was ist eigentlich hier genau mit "Klassen zu Laufzeit laden" gemeint?
Eine Instanz per 'new' auf dem Heap anlegen.
öhm dann würde mich mal interessieren, wieso das in C++ ncht geht soll^^ - hab ich was verpasst?
Wobei eine Instanz aufm Heap ablegen, würde ich eher als Objekt zur Laufzeit laden bezeichnen ... Klassen zur Laufzeit laden hieße meinem Gefühl nach, dass man die Klassendefinition zur Laufzeit kennt -> wie ein Vorredner schon angesprochen hat, über DLLs machbar.
-
audacia schrieb:
In vielen Fällen weiß es nicht der Compiler, sondern frühestens der Linker. Und solange der ein C-Linker bleibt, hat er keinen Eingriff in den Compiliervorgang.
Also ne moderne IDE kann doch anzeigen, ob es mehrere gleiche methoden gibt, wenn ich von nem Aufruf zur Definition springen will. So schwer kann das nicht sein.
Und außerdem gibts DLLs, mit denen sowas wie "Klassen zur Laufzeit laden" praktikabel ist

Da muss aber vorher die Deklaration bekannt sein, oder?
mikey schrieb:
Was ist eigentlich hier genau mit "Klassen zu Laufzeit laden" gemeint?
Eine Instanz per 'new' auf dem Heap anlegen.
Nein.
Sowas wie in Java Class.forName und Methodennamen per Reflection ermitteln und das ganz Zeug.
-
www.de schrieb:
Also ne moderne IDE kann doch anzeigen, ob es mehrere gleiche methoden gibt, wenn ich von nem Aufruf zur Definition springen will. So schwer kann das nicht sein.
...
Da muss aber vorher die Deklaration bekannt sein, oder?Ich sehe schon, du bedarfst eines Beispiels.
// mylib.hpp struct MyNotPolymorphicClass { void doSomething (void) {} };// mydll.hpp #ifdef DLL #define EXPORT __declspec (dllexport) #else #define EXPORT __declspec (dllimport) #endif #include "mylib.hpp" EXPORT void doSomethingWithObject (MyNotPolymorphicClass& obj);// mydemoproject.cpp #include "mylib.hpp" #include "mydll.hpp" int main (void) { MyNotPolymorphicClass mnpc; doSomethingWithObject (mnpc); // hier wirds interessant }// mydll.cpp #include "mydll.hpp" #include <windows.h> struct MyNotPolymorphicButStupidlyDerivedClass : MyNotPolymorphicClass { void doSomething (void) {} }; EXPORT void doSomethingWithObject (MyNotPolymorphicClass& obj) { obj.doSomething (); }Angenommen, ein Compiler ginge aus von dem, was er sieht, und deklarierte dementsprechend Funktionen virtuell. Wenn du mydemoproject.cpp kompilierst, sieht dein hypothetischer Compiler die Definition von MyNotPolymorphicClass, aber keine abgeleitete Klasse, implementiert die Funktion folglich nicht virtuell. Kompilierst du die DLL, so sieht er Basisklasse und Derivat und implementiert die Funktion virtuell. Beide kommen erst zur Laufzeit zusammen.
Was im Beispiel passieren würde, ist offensichtlich: in der main()-Funktion wird auf dem Stack ein Objekt einer nicht polymorphen Klasse erstellt und an die DLL-Funktion doSomethingWithObject() übergeben. Diese ist innerhalb der DLL implementiert, wo der Compiler aufgrund des Vorhandenseins einer abgeleiteten Klasse die Funktion als virtuell ansieht und über die V-Table aufruft. Das übergebene Objekt hat aber gar keine V-Table - das Programm erzeugt eine fatale AV und stürzt ab.
An die Kritiker: natürlich hätte man das auch einfach anhand zweier verschiedener Objektdateien demonstrieren können. So jedoch entsteht gar nicht erst die Diskussion, ob der Linker so eine Aufgabe nicht übernehmen könne.
-
mikey schrieb:
Was ist eigentlich hier genau mit "Klassen zu Laufzeit laden" gemeint?
Eine Instanz per 'new' auf dem Heap anlegen.

-
mikey schrieb:
Was ist eigentlich hier genau mit "Klassen zu Laufzeit laden" gemeint?
Eine Instanz per 'new' auf dem Heap anlegen.
nee, mehr so wie dcom, corba, (und Java, siehe www.de) und sowas das machen, also interfaces dynamisch laden und dann objekte davon instanziieren. in C++ sind klassen ja statisch d.h. auf dem 'C++ compile time level' geht sowas nicht...
