Wieso sind Funktionen in Klassen nicht per default virtell?
-
Mich würde mal interessieren: Wieso sind Funktionen in Klassen nicht per default virtell? Ein Beispiel:
#include <iostream> using namespace std; class Basis { void Funktion () { cout<<"Basis"; } }; class Abgeleitet: public Basis { void Funktion () { cout<<"Abgeleitet"; } }; int main () { Basis *objekt=new Abgeleitet; objekt.Funktion (); delete objekt; }Das Programm gibt das Wort "Basis" aus. Hätte ich vor die Funktion in der Basisklasse ein virtual geschrieben, hätte es "Abgeleitet" ausgegeben.
Aber ist die Variante mit virtual nicht das, was man so ziemlich immer haben will? Wäre die obige Variante nicht die Ausnahme? Wieso also definiert der Standard, daß man Funktionen explizit als virtual deklarieren muß, wenn sie virtuell sein sollen? Wieso ist das nicht der Normalzustand, während nicht-virtuelle Funktionen extra gekennzeichnet werden müssen?
Das gleiche mit diesem const hinter einer Klassenfunktion. Der Compiler kann doch selbst rausfinden, ob eine Funktion eine Membervariable ändert und der Funktion dann entsprechend das Attribut geben oder es sein lassen. Warum muß man das immer extra hinschreiben?
Gibt es dafür reale Gründe oder sind das nur Unzulänglichkeiten des Standards?
-
Eigentlich sind weniger virtuelle Funktionen in einem Programm vorhanden als non-virtuelle.
Zweitens: das const gibst du an, damit der compiler prüft, dass du auch ja nichts veränderst und nicht umgekehrt.
-
Virtuelle Funktionen sind langsamer als nicht virtuelle.
mfg.
-
Nunja, man kann auch fragen, warum man einen ctor immer explizit explizit machen muss.

Letztendlich besteht erstmal kein Grund, dass eine Funktion virtuell ist. Erst wenn Vererbung und Polymorphismus ins Spiel kommt, besteht Bedarf. Das kannst du aber nicht als default Verhalten von OO voraussetzen.Was das const betrifft, ich denke ein Compiler könnte schon selbst entscheiden, ob eine Funktion const ist oder nicht. Nur wer soll dann noch durchblicken, wenn da nichts steht? Dass du const hinschreibst, ist vielmehr eine Hilfe für den Programmierer, damit er weiss was los ist.
-
Eigentlich sind weniger virtuelle Funktionen in einem Programm vorhanden als non-virtuelle.
Wie kommst Du darauf? Also meiner Meinung nach müßte man bei einer Klassendefinition immer alle Funktionen virtuell machen, damit jemand, der davon ableitet, auch die Möglichkeit hat, daß bei
Basis *objekt=new Abgeleitet; objekt.Funktion ();seine überschriebene Funktion aufgerufen wird und nicht die der Basisklasse. Wieso sagst Du also generell, daß es weniger virtuelle Methoden gibt?
Letztendlich besteht erstmal kein Grund, dass eine Funktion virtuell ist. Erst wenn Vererbung und Polymorphismus ins Spiel kommt, besteht Bedarf.
Naja, aber man kann Vererbung ja nicht verhindern. Sollte man also seine Memberfunktionen nicht immer virtual machen, damit jemand, der davon etwas ableitet, eben nicht obiges Problem bekommt?
Was das const betrifft, ich denke ein Compiler könnte schon selbst entscheiden, ob eine Funktion const ist oder nicht. Nur wer soll dann noch durchblicken, wenn da nichts steht?
Wieso muß man auch diesbezüglich überhaupt durchblicken? Ich meine, was interessiert es mich, ob diese oder jene Funktion intern eine Variable ändert? Das geht doch sowieso niemanden außer den Programmierer der Klasse was an. Ich meine, es gibt ja bei Funktionen auch nicht die Möglichkeit, zu gucken, ob eine übergebener Parameter verändert wird. Was ich meine: Wenn ich mir die Headerdatei angucke, weiß ich auch nicht, ob eine Setter-Funktion so:
void Klasse::SetIrgendwas (int parameter) { membervariable=parameter; }oder so:
void Klasse::SetIrgendwas (int parameter) { if (parameter<1 || parameter>10) parameter=1; membervariable=parameter; }arbeitet. Eben weil es in dem Sinne niemanden interessiert, das ergibt sich aus dem Zusammenhang. Und genauso sollte sich auch aus dem Zusammenhang ergeben, ob eine Funktion intern irgendwelche Variablen verändert. Demnach finde ich die explizite Kennzeichnung mit const überflüssig. Das sollte automatisch gemacht werden.
Und nochmal zur Aussage:
das const gibst du an, damit der compiler prüft, dass du auch ja nichts veränderst und nicht umgekehrt.
Das würde ja lediglich bedeuten, daß ich mich vor mir selbst schütze. Und ich denke, das sollte nicht das Ziel sein. Immerhin gehen ja auch Sachen, wie:
class Klasse { private: int zahl; public: void Fkt (Klasse *parameter) { parameter.zahl=7; } };Und nach der Logik "damit prüft der Compiler, daß Du auch ja nichts änderst/falsch machst/was auch immer" sollte das auch nicht funktionieren, denn parameter ist ein fremdes Objekt und seine Variable zahl ist privat, also sollte man sie an der obigen Stelle gar nicht verändern dürfen. Und trotzdem kann man es. Eben, weil parameter ein Zeiger auf ein Objekt von der Klasse ist, in der wir uns gerade befinden. Und darin hab ich eben vollen Zugriff auf die Variablen, egal, ob es sich nun um das eigene Objekt (quasi *this) oder um ein anderes Objekt der Klasse handelt, das ich per Parameter übergebe.
-
Hallo,
Virtuelle Funktionen sind langsamer als nicht virtuelle.
Da schließe ich mich gerne an. Die ganzen Vtbls und Vptrs sind schon leicht performancelastig und nicht nur die.
MFG winexec*
-
Also ich brauche im allgemeinen mehr non-virtuelle Funktionen als virtuelle. Mit den virtuellen Funktionen will man dem User ja nur bestimmte Möglichkeiten geben, Einfluss zu haben. Ansonsten kannst du ihm ja gleich die Klasse an sich übergeben, welche er ändern soll. Bringt ja nix, wenn du von einer Klasse erbst, aber alle Funktionen der Basisklasse überschreibst und neu definierst, dann hast du im Endeffekt dann eine komplett andere Klasse. In gewissen Situationen mag dies vielleicht sinnvoll sein, aber in den meisten sicherlich nicht.
Und zu dem const. Ich brauche das eigentlich nicht, aber ich frage mich grad hat des eigentlich sonst noch einen Einfluss ausser, dass es einem überprüft? Also kann der Compiler irgendwas besseres draus machen, wenn da ein const steht oder kann der Compiler es schneller verarbeiten? Wenn nicht ist es halt ein nettes Gadget, gerade wohl für grosse Projekte. So kann ein anderer sich sicher sein, dass wenn er die oder diejenige Funktion aufruft, er wirklich nur Daten holt und nix an der Klasse verändert.
Grüssli
-
joomoo schrieb:
Virtuelle Funktionen sind langsamer als nicht virtuelle.
mfg.
Meinst du nicht eher, das der Aufruf einer virtuellen Methode langsamer ist? Der Rumpf wird dagegen gleich schnell abgearbeitet.
In C++ heißt es (und darauf besteht auch das ISO-C++ Komitee weiterhin): "Du sollst nicht für etwas bezahlen, was du nicht nutzt."
Der einen vtable-Aufruf ist halt ein Taktzyklus (oder was kostet der heute?) langsamer als ein Aufruf einer nicht virtuellen Methode. Wenn ich 1 Mio. Objekte der Reihe nach aufrufe bzw. ihre virtuellen Methode, hab ich 1 Mio. Taktzyklen zusätzlich verbraten. Das kann sich z.B. auf Hochlastsystemen schon summieren (bei einer GUI-Mainstream-Anwendung wird sowas dagegen nicht auffallen!). Und ich denke, hier hat und _muß_ C++ weiter seinen Vorteil ausspielen! Nämlich in jeder Situation in hoch komplexen Systemen schneller sein als die Konkurrenz. Ich weiß nicht wie Fortran arbeitet, aber Fortran wird ja auch gerne noch eingesetzt. Ich denke mal, auch aus Performancegründen... kenne aber Fortran nur vom hören sagen.
Wäre alles virtuell, würde jeder Methodenaufruf wahrscheinlich grundlos langsam sein. Schau dir mal die STL an: die verträgt eigentlich keine polymorphie. Alles auf Performance ausgelegt.
-
Virtuelle Funktionen sind langsamer als nicht virtuelle.
Ja, gut, wenn das wirklich einen Unterschied ausmacht, dann ist das natürlich nachvollziehbar.
Doch trotzdem noch einen Satz zu
Bringt ja nix, wenn du von einer Klasse erbst, aber alle Funktionen der Basisklasse überschreibst und neu definierst, dann hast du im Endeffekt dann eine komplett andere Klasse.
Klar, würde er alle überschreiben, wäre das sinnlos. Aber es kann ja sein, daß in der abgeleiteten Klasse nur eine Funktion überschrieben wird. Und da der Programmierer der Basisklasse nicht weiß, welche das sein wird, muß er eben, wenn er mit Vererbung rechnet, jede Funktion virtuell machen.
-
Zu deinem const und das hier etwas:
lass Klasse { private: int zahl; public: void Fkt (Klasse *parameter) { parameter.zahl=7; } };Erstmal muss das so aussehen

parameter->zahl=7;Wenn du doch schon ein Parameter siehst der einen Zeiger erwartet, dann muss du auch damit rechnen das das übergebene Argument verändert werden kann.
Die Stärke von const-Elementfunktionen liegt auch noch woanders,
als die erwähnten Punkte:Konstante Objekte: Du kannst für Konstante Objekte festlegen wie sie sich verhalten sollen, bestes Beispiel ist hier op[].
Und nochwas wichtiges: Da man Parameter ja aus effiziens Gründen immer als Refernzen auf const deklarieren sollte, ist es natürlich auch sinnvoll man hat Konstante Elementfunktionen, denn ansonsten könntest du mit den Übergebenen Objekten ja fast gar nicht arbeiten...
Und wenn du irgendwann mal ein größerer Projekt angehen solltest, wirst du darüber froh sein das es sowas wie const gibt...
-
Klar, würde er alle überschreiben, wäre das sinnlos. Aber es kann ja sein, daß in der abgeleiteten Klasse nur eine Funktion überschrieben wird. Und da der Programmierer der Basisklasse nicht weiß, welche das sein wird, muß er eben, wenn er mit Vererbung rechnet, jede Funktion virtuell machen.
Eben, wenn er damit _rechnet_. Und was ist, wenn er das nicht will?
In C++ ist das garnichtmal so unwahrscheinlich. Ein Objekt zu wrappen(also anstatt über Vererbung die neue Funktionalität über komposition zu integrieren) ist meist einfacher. Viele Klassen sind so komplex, dass du nicht nur eine sache, sondern gleich mehrere ändern musst, und dann wird das mit der Vererbung schon komplizierter.
Auch gibt es in C++ über templates andere Möglichkeiten, die funktionalität einer Klasse den eigenen wünschen anzupassen, wenn man keine Vererbung zulassen will, aber das ist ein ganz anderes thema, mit dem man Bücher füllen kann.Und mit einem virtuell als standard zwingst du den programmierern ein Verhalten auf, dass sie vielleicht garnicht wollen.
-
Gestern wars ja schon spät als ich antwortete, also jetzt nochmal etwas ausführlicher:
Wenn du wirklich eine Klasse hast wo jede Methode virtuell sein muss (also nen Interface oder eine abstrakte Klasse), dann fügst du das virtual hinzu.
Aber oft brauchst du das gar nicht, schau dir doch einmal die ganzen STL-Klassen an, da wird so etwas meist gar nicht gebraucht, weil eine Liste so schon alle Funktionen die du brauchst besitzt, was du eher möchtest ist die Art der Speicherallokaierung zu steuern, oder bei der String-Klasse das Verhalten bei vergleichen usw.
Und das kannst du über die Policies erreichen. Policies sind viel flexibler um das Verhalten zu steuern als es Vererbung ist. Schau dir mal in der Loki-Lib (gibts auf sourceforge.net) den Smart-Pointer an, da wird alles über Policies geregelt und der Smart-Pointer selbst ist nur eine sehr kleine Klasse. Alles was man da noch braucht ist ein typedef SmartPtr< SingleThreaded, MeyersSingleton > MySmartPtr und du hast deinen gewünschten SmartPtr. Wenn du für jede mögliche Kombination eine eigene Klasse ableiten würdest wäre das viel mehr Schreibaufwand, vom Wartungsaufwand mal ganz zu schweigen.Zu dem const:
Man schreibt ein const hinter eine Methode um dem Compiler zu sagen, dass diese Funktion das Objekt nicht verändert (damit ist die Methode auch für const-Instanzen aufrufbar). Wenn man nun doch versucht darin etwas zu ändern (versehentlich), dann sagt der Compiler dir das.
Wenn diese Änderung aber nicht den logischen Zustand des Objekts ändert sondern nur ein Implementierungsdetail, dann ist das trotzdem möglich, mit mutable://String-Klasse Version1.0 class String { public: size_t length() const; private: char* str; }; size_t String::length() const { return strlen( str ); } //Aufrufbar auch für einen const String: const String mystring; mystring.length();//Version 2.0 class String { public: size_t length() const; private: mutable size_t len; char* str; }; size_t String::length() const { return len; } //Aufrufbar auch für einen const String: const String mystring; mystring.length();
-
Hallo,
Kostenpunkt bei virtuellen Funktionen:
Man muss für jedes Objekt einen Zeiger zahlen. Wenn nun deine Objekte klein sind, dann können die Kosten beträchtlich sein. Es kann sogar dazu kommen, dass sich die Größe eines Objektes durch Vptrs verdoppelt.
Wenn man ein kleines Betriebssystem gebastelt hat und es noch nicht ganz perfekt ist und man durch virtuelle Funktionen Objekte in einer Gesamtgröße von über 50MB erstellt, dann könnten virtuelle Funktionen doch nicht so harmlos sein.
MFG winexec*
-
Also wenn ich mir diesen Thread so durchlese, frage ich mich, wieviele
von euch sogenannten C++ Programmieren jemals richtig objektorientiert
programmiert haben
C++-ler schrieb:
Eigentlich sind weniger virtuelle Funktionen in einem Programm vorhanden als non-virtuelle.
Ihr schreibt anscheinend hauptsächlich reine C-Programme, vereinzelt garniert
mit ein oder zwei abgeleiteten Klassen als Alibi.Und wenn ihr euch über Performance virtueller Funktionen/Methoden so
aufregt, bleibt doch gleich bei C. Die Sprache behauptet zumindest nicht
objektorientiert zu sein und man muß sich auch nicht verstellenAlan Kay schrieb:
Ich habe den Begriff »Objektorientiert« erfunden, und ich kann Ihnen sagen, ich hatte wahrlich etwas anderes als C++ im Kopf.
BTW: C++-ler's Ausführungen zur Bedeutung des const-Modifiers kann ich vollkommen
zustimmen.Dieses const ist eines der Sprachattribute die ich in Java vermisse

-
Javaner schrieb:
Also wenn ich mir diesen Thread so durchlese, frage ich mich, wieviele
von euch sogenannten C++ Programmieren jemals richtig objektorientiert
programmiert haben
Nein, das kannst du so nicht sagen. Du mußt bedenken, das wir in C++ ganz andere Sprach-Features haben, die in Java nicht vorhanden sind. Ich selbst programmiere beruflich Java, weiß also sehr wohl was OOP ist und bin auch gezwungen es so zu machen. In C++ habe ich aber z.B. Templates und Mehrfachvererbung, wo ich mit diesen beiden _kombinierten_ Features die Policy-Patterns einsetzen kann (Aspektorientiertes Design), was ich in Standard-Java praktisch nicht umsetzen kann.
Klar, jeder kann in C++ wie in Java programmieren, auch ich ertappe mich immer wieder, das ich das so mache, weil ich es vom Beruf her so gewohnt bin. Aber das ist ja das Tolle an C++: ich kann in C++ so programmieren, wie ICH es will.
-
@ Artchi
Als Wanderer zwischen den Welten kannst du mir
sicher mal die Hauptunterschiede zwischen C++- und
Java-Templates aufzählen.Ich weiß nur, daß Java intern ohne Code-Kopieren auskommt.
Gibt es Einschränkungen? Kann man mit C++-Templates etwas machen,
was in Java nicht möglich ist?
-
Javaner schrieb:
Kann man mit C++-Templates etwas machen,
was in Java nicht möglich ist?Schnell ausführen. f'`8k
Gruß, TGGC (\-/ returns)
-
Auch 'ne Antwort

-
Javaner schrieb:
Als Wanderer zwischen den Welten kannst du mir
sicher mal die Hauptunterschiede zwischen C++- und
Java-Templates aufzählen.Die "Java Templates" heißen Generics und haben außer der Syntax fast nichts mit den C++ Templates gemein. Die darf man nicht 1:1 vergleichen.
Gibt es Einschränkungen? Kann man mit C++-Templates etwas machen,
was in Java nicht möglich ist?Joah, z.B. die Fakultät zur Compile-Time berechnen:
template <u64 N> struct Faculty { enum { result = N * Faculty<N-1>::result }; }; template < > struct Faculty<1> { enum { result = 1 }; }; std::cout<<Faculty<3>::result<<std::endl;Auch cool finde ich solche Sachen, egal in welcher Sprache. Generische Programmierung rockt halt^^:
//Filtern wir mal alle geraden zahlen raus template <class T1, class T2> struct Mod : public unary_function<T1, T2> { T2 operator()(const T1& x) const { return x%2==0; } }; template < class Func, class Cont, class Iter> Cont filter(const Cont &c) { Func f; Cont ret; for (Iter it = c.begin(); it != c.end(); ++it) if ( f(*it) == true) ret.push_back(*it); return ret; }; std::vector<int> v; for (int i=0;i<50;++i) v.push_back(i); std::vector result = filter< Mod<int, bool>, std::vector<int>, std::vector<int>::iterator > (v);Oder Policy-Design. Wurde ja schon erwähnt.
MfG
GPC
-
NES-Spieler schrieb:
Naja, aber man kann Vererbung ja nicht verhindern. Sollte man also seine Memberfunktionen nicht immer virtual machen, damit jemand, der davon etwas ableitet, eben nicht obiges Problem bekommt?
Es gibt ja nicht nur public Vererbung. Und man will auch nicht immer, dass die Funktion überschrieben wird. Manchmal reicht halt auch Überdeckung einfach aus. Schau dir zB mal die STL an, wie es hier schon erwähnt wurde. Da wirst du nicht sooo viele virtuelle Funktionen finden. Auch ist Vererbung nicht immer das geeignete Mittel der Wahl. In der STL wirst du zB Container finden, die über Layering implementiert sind. Stichwort: "ist ein", "hat ein" Beziehung.
Wieso muß man auch diesbezüglich überhaupt durchblicken? Ich meine, was interessiert es mich, ob diese oder jene Funktion intern eine Variable ändert? Das geht doch sowieso niemanden außer den Programmierer der Klasse was an. Ich meine, es gibt ja bei Funktionen auch nicht die Möglichkeit, zu gucken, ob eine übergebener Parameter verändert wird.
Ich weiss nicht, ob du mich überhaupt verstanden hast. Dass const existiert, sollte hoffentlich klar sein. Damit du ein Objekt erzeugen kannst, welches nach der Initialisierung konstant bleibt und nicht mehr verändert werden kann (const_cast ignorieren wir einfach mal). Wenn du also so ein const Objekt hast, willst du dann erstmal deinen Code schreiben und hinterher beim Kompilieren schauen, ob die Memberfunktionsaufrufe vom Compiler akzeptiert werden? Oder wie willst du herausfinden, ob eine Memberfunktion für const Objekte zulässig ist? Immer in die Dokumentation schauen, ob da ein entsprechender Vermerk steht? Dann kannst du auch gleich const hinter die Funktion schreiben. So kann man doch kein vernünftiges Design planen. Dass das const ein weiterer Schutzmechanismus für den Entwickler ist, der ungewolltes Verändern von Membern verhindert, wurde ja auch schon erwähnt.
Und nochmal zur Aussage:
das const gibst du an, damit der compiler prüft, dass du auch ja nichts veränderst und nicht umgekehrt.
Das würde ja lediglich bedeuten, daß ich mich vor mir selbst schütze.
U.a. Ist es nicht toll, wenn dir der Compiler sagt, dass du einen Fehler gemacht hast?
Und nach der Logik "damit prüft der Compiler, daß Du auch ja nichts änderst/falsch machst/was auch immer" sollte das auch nicht funktionieren, denn parameter ist ein fremdes Objekt und seine Variable zahl ist privat, also sollte man sie an der obigen Stelle gar nicht verändern dürfen.
Das ist aber ein ganz anderes Gebiet. Zwar ist es ein anderes Objekt, aber nunmal dieselbe Klasse. Ob das jetzt richtig ist oder nicht, darüber kann man diskutieren. C++ erlaubt es und fertig.
Javaner schrieb:
Also wenn ich mir diesen Thread so durchlese, frage ich mich, wieviele
von euch sogenannten C++ Programmieren jemals richtig objektorientiert
programmiert haben
Tja, und wenn ich mir deinen Nick anschaue, dann vergleichst du Java mit C++. Das ist aber genauso wenig sinnvoll, wie C mit C++ zu vergleichen.
Java _ist_ objektorientiert, C++ nicht (auch wenn BS die Sprache deswegen entwickelt hat). C++ ist eine Multiparadigmensprache, und OO lediglich ein verwendbares Konzept. Und das ist auch das Schöne an C++, es bietet weitaus mehr als nur Interfaces. Ob du das nun verstehst oder nicht. "It's not a bug, it's a feature."
Javaner schrieb:
Ihr schreibt anscheinend hauptsächlich reine C-Programme, vereinzelt garniert
mit ein oder zwei abgeleiteten Klassen als Alibi.Und du hast offensichtlich nicht viel Ahnung von C++. Sry, aber das musste jetzt sein.

Freak_Coder schrieb:
Und nochwas wichtiges: Da man Parameter ja aus effiziens Gründen immer als Refernzen auf const deklarieren sollte, ist es natürlich auch sinnvoll man hat Konstante Elementfunktionen, denn ansonsten könntest du mit den Übergebenen Objekten ja fast gar nicht arbeiten...
Nope. Das eine hat mit dem anderen nichts zu tun. Die übergebenen Parameter sind vollkommen unabhängig von this.