Nehmen wir das mal als Ansatz: Was nützt final dem Compiler oder der Laufzeit?Reduzierst du 'direct' darauf, dass eine Methode nicht weiter überschrieben werden kann musst du das nicht mit einem neuen Keyword machen, dieses Keyword gibts es schon und es nennt sich 'final'.
Wir machen es mal Schrittweise:
Zu (1): Wenn von einer Kindklasse im Rang n geerbt wird, ist die Kindklasse die Basisklasse von der neuen Kindklasse im Rang n+1.[(1)]Ob von einer Kindklasse geerbt wird oder nicht ist doch nicht weiter relevant. [(2)] Fakt ist, dass jemand der die Basisklasse kennt die Kindklasse nicht kennen muss.
Entsprechend gilt mit (2): Wenn man weiss, dass eine Kindklasse im Rang n final ist, dann gibt es keine neue Kindklasse im Rang n+1.
Einverstanden?
Damit ist die Klassenvererbung quasi beschränkt, also [k; n]. Der Compiler kennt aber alle Klassen von k bis n (Ansonsten könntest du keine Kindklasse davon erstellen).
Einverstanden?
Damit löst final das Problem in Richtung n+1. Das Problem in Richtung n-1 ist aber nicht gelöst, sprich die (Base* b = Derived* d). Es kann nämlich sein, dass (wie in deinem Beispiel vor einigen Posts) eine Bibliothek nur die Basisklasse exportiert. Der Compiler, der dann die Bibliothek in sein Programm linkt (Ja, eigentlich macht es der Linker...) kann dann die Definition der Kindklasse nicht kennen.
Einverstanden?
Entsprechend ist es nötig, eine VMT zu benutzen, da der Compiler nicht sicher wissen kann, ob eine Klasse nach aussen gegeben wird oder nicht, und Resultate aufgrund von Vermutungen sind in der Informatik nicht wirklich erwünscht. (Der Compiler soll nichts auf eigene Faust machen).
Einverstanden?
Nun käme die Idee ins Spiel: Der Programmierer sagt dem Compiler: "Hey, ich brauche diese Klasse nur intern und du kennst immer alle Basis- und Kindklassen". (Das ist anders als final, wo der Compiler ausschliesslich das Ende eines Astes einer Baumstruktur kennt. Hier würde er wissen, dass der Compiler den Baum von der Wurzel bis zum Ast kennt und der Baum nicht weiter wächst (auch nicht in Nachbars Garten)).
Einverstanden?
Wird es ja quasi. Der Punkt ist ja gerade, eine statische Klasse aus (per Default) virtuellen zu erzeugen. Nur nicht von der Basisklasse, sondern von irgendeiner Klasse innerhalb des definierten Bereichs.Das direct Keyword würde dann nur Sinn machen, wenn es auf Base angewandt wird, weil dann der Compiler weiss, dass er nach einem Symbol Base::func suchen muss und einen Aufruf darauf verwenden kann und nicht irgendwelche virtuellen Funktionen aufrufen muss. Das würde aber wiederum bedeuten, dass Base gar keine virtuellen Methoden haben muss, da es ja sowieso nicht vererbt werden kann.
Tut er ja auch. Allerdings nur bei Stackinstanzen. Nicht bei Pointern.foo in meinem Beispiel kann nur dann einmal für VMTD und einmal für NoVMTD templateisiert werde, wenn zum Zeitpunkt des Aufrufs der ursprüngliche Code von foo noch bekannt ist. Das ist nur dann der Fall, wenn foo im gleichen Translationunit verarbeitet wird wie der Aufruf an foo. Wenn dem so ist brauchst du das Keyword auch nicht, weil der Compiler/Optimierer dann selber so schlau sein kann das einzubauen, wenn ihm danach ist.
Jetzt aberDamit sie das ist müsste sie, wie du erwähntest, sozusagen als template markiert werden, damit sie nicht in Objektcode sondern in eine ersetzbare Schablone umgewandelt wird. Dazu brauchen wir aber auch kein neues Keyword, dazu kannst du schlicht template verwenden.
C++:
char* ptr = "text";
ptr[3] //brauche ich nicht
(*(ptr + 3)) //Geht ja auch
Ja.Der Compiler/Optimierer kann nun bei jedem Aufruf entscheiden welche Variante er nehmen möchte und wie er das umsetzen will, da es sich ja nur um ein template handelt.
Ok, ich habe mich ein bisschen missverständlich ausgedrückt: Eine Klasse, die polymorph sein kann, aber von der Art, wie Funktionen aufgerufen werden (und damit der Performance) nicht von einer statischen Klasse zu unterscheiden ist.Nein, dann müsstest du deinem keyword noch weitere Eingeschaften hinzufügen. So müsste zum Beispiel Derived von Base immer private erben. Also Derived ist dann kein Base mehr, kann auch nicht mehr in ein Base umgewandelt werden und hat überhaupt keine Relation mehr zu Base, ausser dass es halt die Methoden und Felder einfach übernimmt.
Da hast du Recht. Das Weitergeben, ohne die Informationen für die Basisklassen mitzugeben jedoch schon.Wie erwähnt ist das weitervererben nicht der riskante Punkt davon.
Nun, da ich die Klasse verwende, kann ich sehr wohl entscheiden, ob eine VMT nötig ist. Natürlich ist die Verwendung ausschlaggebend. Aber wenn ich "die Verwendung bin", dann geht das schon.Du kannst bei der Klasse nicht entscheiden ob eine VMT nötig ist oder nicht, das entscheidet die Verwendung. Den Zusammenhang zu new versteh ich nicht. Es ist im Standard klar definiert, was passiert, wenn eine Exception nicht abfangen wird und ein nullptr ist auch nichts undefiniertes.
Zu new: Ja. Man kann ja auch in den Standard schreiben "direct bitte nur sehr bedacht oder Drachen passieren". Natürlich muss man es erst definieren. Aber der Sinn hier ist ja, eine mögliche Definition zu finden, um dem Compiler das zu ermöglichen.
Ah, "nennenswert" ist subjektiv. Ist es im Vergleich zu Dateizugriffen vernachlässigbar? Sicherlich. Im Vergleich zu Heapallocations ebenfalls. Aber wenn eine Möglichkeit besteht, das zu optimieren (wenn auch nur in Spezialfällen), warum sollte man es nicht tun?In der realen Welt hat eine VMT keinen nennenswerten Einfluss auf die Laufzeit.
Klar, wenn du sagst, die VMT gehöre nicht in den Standard, dann verstehe ich das auch, zumindest teilweise. Aber das ist dann ja wieder eine Grundsatzfrage: Macht man einen Seitenzweig des Standards? Definiert man einfach das Keyword und lässt es versanden, wenn eine Möglichkeit gefunden wurde, sämtliche Polymorphie ohne VMT zu betreiben? Und so weiter und so fort.
C ist eben nicht immer schneller als C++. C kennt inlining schlecht (zumindest Standard-C ohne C++), Callbacks sind die Regel. Klar kann man mischen - aber wieso sollte C++ nicht alles versuchen, um die Vorteile von C und jene von OOP zu vereinen?Wo Mikrooptimierungen in diesem Ausmasse nötig sind sollte man gleich auf C umsteigen.
Wot?Dort herrscht generell ja auch die Akzeptanz, dass dich jede Instruktion aus nicht-reproduzierbaren und nicht-debuggbaren Gründen ins Nirvana kicken kann.
Äh. Ein Beispiel bitte. Und nicht irgendwas mit Verwendung von undefinierten Pointern. Also wenn man es hinkriegt, etwas nicht-reproduzierbar und nicht-debuggbar zu machen... Aber noch "Akzeptanz" dafür? "Hey, guck mal. Dein Bremssystem im Auto ist einfach abgeraucht" - "Tja, wurde halt in C geschrieben. Muss man akzeptieren."
Auch C ist nicht der Wild Wild West der Programmierung
Gruss
cwriter