Warum wird eine reine virtuelle Funktion mit 0 initialisiert?

147

Wir deklarieren eine reine virtuelle Funktion immer als:

virtual void fun () = 0 ;

Dh es wird immer 0 zugewiesen.

Ich verstehe, dass dies dazu dient, den vtable-Eintrag für diese Funktion auf NULL zu initialisieren, und jeder andere Wert hier führt zu einem Fehler bei der Kompilierung. Ist dieses Verständnis richtig oder nicht?

Mukeshkumar
quelle
12
Beachten Sie, dass vtable keine Sprachanforderung ist, sondern nur eine Implementierungsoption für virtuelle Methoden. Ein Compiler könnte dieselbe Abstraktion mit einer anderen Implementierung erstellen (dh ohne vtable und ohne dass ein Element 0 ist)
David Rodríguez - dribeas
@hype Re Ihre Zusatzfrage - das sagt meine Antwort (und einige andere).
Nur neugierig, was passiert, wenn ich gebe, virtual void func() = 100;
krithikaGopalakrisnan

Antworten:

161

Der Grund =0dafür ist, dass Bjarne Stroustrup zum Zeitpunkt der Implementierung des Features nicht glaubte, dass er ein anderes Schlüsselwort wie "pure" hinter der C ++ - Community erhalten könnte. Dies wird in seinem Buch The Design & Evolution of C ++ , Abschnitt 13.2.3 beschrieben:

Die neugierige = 0-Syntax wurde gewählt ... weil ich zu diesem Zeitpunkt keine Chance sah, ein neues Schlüsselwort zu akzeptieren.

Er erklärt auch ausdrücklich, dass dies den vtable-Eintrag nicht auf NULL setzen muss und dass dies nicht der beste Weg ist, reine virtuelle Funktionen zu implementieren.


quelle
4
Ja, es ist nur Syntax. Ich habe viele Projekte gesehen, die #define PURE = 0 sind, und sie sagen virtual void Foo () PURE;
i_am_jorf
79
Bitte Gott halte mich von diesen Projekten fern :-)
27
Es ist viel weniger schlimm als #define BEGIN {#define END} ;-) und ich habe das manchmal gesehen.
Toon Krijthe
5
Diese Art von raffinierten Dingen lässt mich denken, dass C ++ nicht sehr ausgefeilt ist. Es ist komisch, wenn man bedenkt, dass es so oft benutzt wird. Ich hoffe, dass die Sprache mit den Tagen besser wird.
Jokoon
19
Mit anderen Worten, Bjarne wurde "mit einer Frist konfrontiert" und "benutzte einen Hack", um einen "Designfehler" zu überwinden;) (nur scherzhaft)
Carl
78

Wie bei den meisten "Warum" -Fragen zum Design von C ++ ist der erste Blick auf das Design und die Evolution von C ++ von Bjarne Stroustrup 1 :

Die merkwürdige =0Syntax wurde der offensichtlichen Alternative der Einführung eines neuen Schlüsselworts vorgezogen, pureoder abstractweil ich zu diesem Zeitpunkt keine Chance sah, ein neues Schlüsselwort zu akzeptieren. Hätte ich vorgeschlagen pure, wäre Release 2.0 ohne abstrakte Klassen ausgeliefert worden. Da ich die Wahl zwischen einer schöneren Syntax und abstrakten Klassen hatte, entschied ich mich für abstrakte Klassen. Anstatt eine Verzögerung zu riskieren und bestimmte Kämpfe zu führen pure, habe ich die traditionelle C- und C ++ - Konvention verwendet, 0 zu verwenden, um "nicht da" darzustellen. Die =0Syntax passt zu meiner Ansicht, dass ein Funktionskörper der Initialisierer für eine Funktion ist, auch zu der (vereinfachten, aber normalerweise angemessenen) Ansicht des Satzes virtueller Funktionen, die als Vektor von Funktionszeigern implementiert werden. [...]

1 §13.2.3 Syntax

Jerry Sarg
quelle
29

Abschnitt 9.2 des C ++ - Standards enthält die Syntax für Klassenmitglieder. Es enthält diese Produktion:

pure-specifier:
    = 0

Der Wert hat nichts Besonderes. "= 0" ist nur die Syntax für "Diese Funktion ist rein virtuell". Es hat nichts mit Initialisierung oder Nullzeigern oder dem numerischen Wert Null zu tun, obwohl die Ähnlichkeit mit diesen Dingen einen mnemonischen Wert haben kann.

Kristopher Johnson
quelle
5
+1 für die Bezugnahme auf den C ++ - Standard. Es ist eine Art Überraschung, dass eine der bestmöglichen Antworten und bisher nur 1 Stimme erhalten hat. Das Lesen des Standards sollte der allererste Schritt sein, um C ++ - Fragen zu lösen.
Mloskot
7
@mloskot: Vielleicht, weil es die Frage des OP nicht beantwortet, nur die Situation neu formuliert?
Nur jemand
6
@just jemand - Es enthält das Standardzitat, das angibt, wie die Syntax der Deklaration einer reinen virtuellen Funktion lautet und dass die Syntax einen reinen Spezifizierer verwendet. = 0Was möchten Sie noch wissen? Es wäre dasselbe wie zu fragen, warum der Funktionskörper mit {} umschlossen ist. Die Antwort wäre, weil dies die C ++ - Syntax definiert.
Mloskot
19

Ich bin mir nicht sicher, ob dahinter eine Bedeutung steckt. Es ist nur die Syntax der Sprache.

cquillen
quelle
16

C ++ hat sich immer gescheut, neue Schlüsselwörter einzuführen, da neue reservierte Wörter alte Programme beschädigen, die diese Wörter als Bezeichner verwenden. Es wird oft als eine der Stärken der Sprache angesehen, dass sie alten Code so weit wie möglich respektiert.

Die = 0Syntax wurde zwar gewählt, da sie dem Festlegen eines vtable-Eintrags ähnelt 0, dies ist jedoch rein symbolisch. (Die meisten Compiler weisen solche vtable-Einträge einem Stub zu, der vor dem Abbrechen des Programms einen Fehler ausgibt.) Die Syntax wurde hauptsächlich gewählt, weil sie zuvor für nichts verwendet wurde und die Einführung eines neuen Schlüsselworts gespeichert wurde.

sbi
quelle
3
+1 zur Erläuterung des Nachteils der Einführung eines neuen Schlüsselworts. Das ist hilfreich, um die Gründe zu verstehen, aber die C ++ - Syntax scheint mir absurd kompliziert zu sein, und ich wünschte, sie hätte sie besser lesbar gemacht - ein pureSchlüsselwort wäre in meinem Buch großartig gewesen. Wie auch immer, es ist gut, die Gründe zu verstehen.
Keith Pinson
@KeithPinson Wenn Sie ein reines Schlüsselwort möchten, können Sie #define pure = 0.
JDH8
@ jdh8: Ugh. Nur ... Ugh.
sbi
Als Randnotiz sagte er in einer Klasse mit Bjarne, er wolle das "reine" Schlüsselwort wirklich in C ++ integrieren ... aber er versuchte es sehr spät im Zyklus, bevor der C ++ - Compiler ausgeliefert werden sollte (IIRC) weniger als zwei Wochen). Angeblich hat es nicht geschafft.
ThePhD
@ThePhD: ISTR sagt er das auch irgendwo in D & E. (Ich bin jedoch zu faul, um es
nachzuschlagen
11

C ++ muss eine Möglichkeit haben, eine reine virtuelle Funktion von einer Deklaration einer normalen virtuellen Funktion zu unterscheiden. Sie entschieden sich für die = 0Syntax. Sie hätten einfach das Gleiche tun können, indem sie ein reines Schlüsselwort hinzugefügt hätten. C ++ ist jedoch ziemlich abgeneigt, neue Schlüsselwörter hinzuzufügen, und bevorzugt die Verwendung anderer Mechanismen zur Einführung von Funktionen.

JaredPar
quelle
2
-0: Wenn Sie selbst nichts Wesentliches zu sagen haben, verwenden Sie ein ausführliches Zitat (siehe Jerry Coffins Antwort für +1;)
nur jemand
7

In diesem Fall ist nichts "initiiert" oder "zugewiesen" Null. = 0in nur einem syntaktischen Konstrukt bestehend aus =und 0Token, das absolut keine Beziehung zu Initialisierung oder Zuweisung hat.

Es hat keine Beziehung zu einem tatsächlichen Wert in "vtable". Die C ++ - Sprache hat keine Vorstellung von "vtable" oder Ähnlichem. Verschiedene "vtables" sind nichts anderes als Details spezifischer Implementierungen.

Ameise
quelle
3

Ich erinnere mich, dass ich gelesen habe, dass die Rechtfertigung für die lustige Syntax darin bestand, dass es einfacher war (in Bezug auf die Akzeptanz von Standards), als ein anderes Schlüsselwort einzuführen, das dasselbe tun würde.

Ich glaube, dies wurde in The Design and Evolution of C ++ von Bjarne Stroustrup erwähnt.

Luke
quelle
2

Ich würde annehmen, dass dies nur ein Teil der C ++ - Grammatik ist. Ich glaube nicht, dass es Einschränkungen gibt, wie die Compiler dies für ein bestimmtes Binärformat tatsächlich implementieren. Ihre Annahme war wahrscheinlich richtig für die frühen C ++ - Compiler.

rui
quelle
2

Das = 0deklariert eine reine virtuelle Funktion .

Es versteht sich, dass hiermit der vtable-Eintrag für diese Funktion auf NULL initialisiert wird und jeder andere Wert hier zu einem Fehler bei der Kompilierung führt

Ich denke nicht, dass das stimmt. Es ist nur eine spezielle Syntax. Die vtable ist implementierungsdefiniert. Niemand sagt, dass ein vtable-Eintrag für ein reines Mitglied bei der Erstellung tatsächlich auf Null gesetzt werden muss (obwohl die meisten Compiler vtables ähnlich behandeln).

Alexander Gessler
quelle
4
Das stimmt eigentlich nicht. Es ist nichts Falsches daran, eine Definition für eine reine virtuelle Funktion bereitzustellen. Das einzige, was Sie tun = 0müssen, ist, die gesamte Klasse abstrakt zu machen und virtuelle Aufrufe von reinen Funktionen zu verbieten . Nicht virtuelle Anrufe sind immer noch vollkommen in Ordnung, wenn die Definition (falls Sie eine angegeben haben) verwendet wird.
AnT
Schauen Sie sich einfach die Godbolt-Ausgabe an. Es gibt keinen Raum für Mehrdeutigkeiten oder Spekulationen. Ich werde später selbst einen Blick darauf werfen
Lewis Kelsey
Es scheint, dass es den Eintrag durch __cxa_pure_virtual arobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/… anstelle von Base :: f () ersetzt
Lewis Kelsey
1

Nun, Sie können den vtable-Eintrag auch initialisieren, um auf eine tatsächliche Funktion zu verweisen. "

 virtual void fun()
 {
     //dostuff()
 }

Es scheint intuitiv zu sein, dass der vtable-Eintrag entweder so definiert werden kann, dass er nirgendwo (0) oder auf eine Funktion zeigt. Wenn Sie Ihren eigenen Wert dafür angeben, wird dieser wahrscheinlich auf Müll anstatt auf eine Funktion verweisen. Aber deshalb ist "= 0" erlaubt und "= 1" nicht. Ich vermute, Neil Butterworth hat Recht damit, warum "= 0" überhaupt verwendet wird

Brian
quelle
1
Sogar ich hatte eine ähnliche Meinung, aber da viele Standards und Bjarnes Kommentare dazu zitiert haben, haben wir nur minimale Argumentationschancen :)
Mukeshkumar