Dlaczego czysta funkcja wirtualna jest inicjowana przez 0?

147

Zawsze deklarujemy czystą funkcję wirtualną jako:

virtual void fun () = 0 ;

To znaczy, zawsze jest przypisane do 0.

Rozumiem, że ma to na celu zainicjowanie wpisu vtable dla tej funkcji na NULL, a każda inna wartość tutaj powoduje błąd czasu kompilacji. Czy to rozumienie jest poprawne, czy nie?

mukeshkumar
źródło
12
Zauważ, że vtable nie jest wymaganiem językowym, ale tylko opcją implementacji metod wirtualnych. Kompilator mógłby stworzyć tę samą abstrakcję z inną implementacją (to znaczy bez vtable i bez żadnego elementu, który zawiera 0)
David Rodríguez - dribeas
@hype Re Twoje dodatkowe pytanie - tak mówi moja odpowiedź (i kilka innych).
Po prostu ciekawy, co się stanie, jeśli dam, virtual void func() = 100;
krithikaGopalakrisnan

Odpowiedzi:

161

Powodem =0jest to, że Bjarne Stroustrup nie sądził, że mógłby uzyskać inne słowo kluczowe, takie jak „czysty”, poza społeczność C ++ w czasie, gdy funkcja była implementowana. Jest to opisane w jego książce The Design & Evolution of C ++ , sekcja 13.2.3:

Wybrano składnię curious = 0 ... ponieważ w tamtym czasie nie widziałem żadnej szansy na zaakceptowanie nowego słowa kluczowego.

Stwierdza również wyraźnie, że nie musi to ustawiać wpisu vtable na NULL i że nie jest to najlepszy sposób implementacji czystych funkcji wirtualnych.


źródło
4
Tak, to tylko składnia. Widziałem wiele projektów, w których #define PURE = 0 i powiedzą virtual void Foo () PURE;
i_am_jorf
79
Proszę Boże, trzymaj mnie z daleka od tych projektów :-)
27
Jest dużo mniej gorszy niż #define BEGIN {#define END} ;-) i czasami to widziałem.
Toon Krijthe
5
Ten rodzaj fajnej rzeczy sprawia, że ​​myślę, że C ++ nie jest zbyt dopracowany. To dziwne, biorąc pod uwagę, że jest tak często używane. Mam nadzieję, że z upływem dni język będzie lepszy.
żart
19
Tak więc, innymi słowy, Bjarne „stanął przed terminem” i „wykorzystał hack”, aby ominąć „błąd projektowy”;) (Po prostu żartobliwie)
Carl
78

Podobnie jak w przypadku większości pytań „Dlaczego” dotyczących projektu C ++, pierwsze miejsce, na które należy zwrócić uwagę, to Projekt i ewolucja C ++ autorstwa Bjarne Stroustrup 1 :

Ciekawa =0składnia została wybrana zamiast oczywistej alternatywy wprowadzenia nowego słowa kluczowego purelub abstractdlatego, że w tamtym czasie nie widziałem żadnej szansy na zaakceptowanie nowego słowa kluczowego. Gdybym zasugerował pure, wydanie 2.0 byłoby dostarczane bez klas abstrakcyjnych. Mając do wyboru ładniejszą składnię i klasy abstrakcyjne, wybrałem klasy abstrakcyjne. Zamiast ryzykować opóźnienia i ponosić pewne kłótnie pure, użyłem tradycyjnej konwencji C i C ++, zgodnie z którą 0 oznacza „nie ma”. W =0składni pasuje moim zdaniem, że ciało funkcji jest inicjator dla funkcji również z (uproszczone, ale zazwyczaj odpowiedniej) Biorąc pod uwagę zestaw funkcji wirtualnych realizowanego jako wektor wskaźników funkcji. […]

1 §13.2.3 Składnia

Jerry Coffin
źródło
29

Sekcja 9.2 standardu C ++ podaje składnię dla członków klasy. Obejmuje tę produkcję:

pure-specifier:
    = 0

Nie ma nic specjalnego w tej wartości. „= 0” to po prostu składnia wyrażająca „ta funkcja jest czysto wirtualna”. Nie ma to nic wspólnego z inicjalizacją, wskaźnikami zerowymi lub wartością liczbową zero, chociaż podobieństwo do tych rzeczy może mieć wartość mnemoniczną.

Kristopher Johnson
źródło
5
+1 za odwołanie się do standardu C ++. To trochę zaskakujące, że jedna z najlepszych możliwych odpowiedzi i do tej pory tylko 1 głos. Przeczytanie standardu powinno być pierwszym krokiem do rozwiązania pytań w C ++.
mloskot
7
@mloskot: może dlatego, że nie odpowiada na pytanie OP, tylko przedstawia sytuację?
tylko ktoś
6
@ just somebody - zawiera standardowe cytowanie, które określa składnię deklaracji czystej funkcji wirtualnej i że składnia używa czystego specyfikatora. = 0Co jeszcze chciałbyś wiedzieć? Byłoby to tym samym, co pytanie, dlaczego treść funkcji jest opakowana w {} Odpowiedź byłaby taka, ponieważ to właśnie definiuje składnia C ++.
mloskot
19

Nie jestem pewien, czy ma to jakieś znaczenie. To tylko składnia języka.

cquillen
źródło
16

C ++ zawsze unikał wprowadzania nowych słów kluczowych, ponieważ nowe zastrzeżone słowa łamią stare programy, które używają tych słów jako identyfikatorów. Często uważa się, że jedną z mocnych stron języka jest to, że w miarę możliwości szanuje stary kod.

= 0Składnia może rzeczywiście zostały wybrane, ponieważ przypomina ustawienie vtable wpisu do 0, ale jest czysto symboliczny. (Większość kompilatorów przypisuje takie wpisy vtable do odgałęzienia, które emituje błąd przed przerwaniem programu.) Składnia została wybrana głównie dlatego, że nie była wcześniej używana i zapisała wprowadzenie nowego słowa kluczowego.

sbi
źródło
3
+1 za wyjaśnienie wady wprowadzenia nowego słowa kluczowego. Jest to pomocne, aby zrozumieć uzasadnienie, ale składnia C ++ wydaje mi się absurdalnie zagmatwana i chciałbym, aby uczyniły ją bardziej czytelną dla człowieka - puresłowo kluczowe byłoby świetne w mojej książce. W każdym razie dobrze jest zrozumieć uzasadnienie.
Keith Pinson
@KeithPinson Jeśli potrzebujesz czystego słowa kluczowego, możesz #define pure = 0.
jdh8
@ jdh8: Ugh. Po prostu ... Ugh.
sbi
Na marginesie, na zajęciach z Bjarne powiedział, że naprawdę chciał umieścić słowo kluczowe "pure" w C ++ ... ale próbował je dostać na bardzo późnym etapie cyklu, zanim kompilator C ++ miał zostać wysłany (IIRC mniej niż dwa tygodnie). Pozornie nie udało się.
ThePhD
@ThePhD: ISTR mówi to również gdzieś w D&E. (Jestem zbyt leniwy, żeby to sprawdzić.)
sbi
11

C ++ musi mieć sposób na odróżnienie czystej funkcji wirtualnej od deklaracji normalnej funkcji wirtualnej. Zdecydowali się użyć = 0składni. Mogli po prostu zrobić to samo, dodając czyste słowo kluczowe. Ale C ++ nie chce dodawać nowych słów kluczowych i woli używać innych mechanizmów do wprowadzania funkcji.

JaredPar
źródło
2
-0: kiedy nie masz nic konkretnego do powiedzenia, użyj obszernego cytatu (zobacz odpowiedź Jerry'ego Coffina na +1;)
po prostu ktoś
7

W tym przypadku nic nie jest „inicjowane” ani „przypisywane” zero. = 0tylko w konstrukcji składniowej składającej się z tokenów =i 0, która nie ma absolutnie żadnego związku ani z inicjalizacją, ani przypisaniem.

Nie ma związku z żadną rzeczywistą wartością w „vtable”. W języku C ++ nie ma pojęcia „vtable” ani nic podobnego. Różne „vtables” to nic innego jak tylko szczegóły konkretnych implementacji.

Mrówka
źródło
3

Pamiętam, jak czytałem, że uzasadnieniem zabawnej składni było to, że było to łatwiejsze (pod względem akceptacji standardów) niż wprowadzenie innego słowa kluczowego, które robiłoby to samo.

Myślę, że zostało to wspomniane w książce The Design and Evolution of C ++ autorstwa Bjarne Stroustrup.

Łukasz
źródło
2

Przypuszczam, że to tylko część gramatyki C ++. Nie sądzę, aby były jakieś ograniczenia co do tego, jak kompilatory faktycznie implementują to dla danego konkretnego formatu binarnego. Zakładasz, że prawdopodobnie było to właściwe dla wczesnych kompilatorów C ++.

rui
źródło
2

= 0Deklaruje czystą funkcję wirtualną .

Zrozumiałe jest, że ma to na celu zainicjowanie wpisu vtable dla tej funkcji na NULL, a każda inna wartość tutaj powoduje błąd czasu kompilacji

Nie sądzę, że to prawda. To tylko specjalna składnia. Tabela vtable jest zdefiniowana w ramach implementacji. Nikt nie mówi, że wpis vtable dla czystego elementu członkowskiego musi być w rzeczywistości wyzerowany podczas konstrukcji (chociaż większość kompilatorów obsługuje podobnie vtables).

Alexander Gessler
źródło
4
To właściwie nieprawda. Nie ma nic złego w podawaniu definicji czystej funkcji wirtualnej. Jedyne co = 0robi to abstrakcja całej klasy i zabrania wirtualnych wywołań czystych funkcji. Nie-wirtualne wywołania są nadal całkowicie OK, czyli wtedy, gdy używana jest definicja (jeśli została podana).
AnT
Wystarczy spojrzeć na wyjście godbolt. Nie ma miejsca na dwuznaczność ani spekulacje. Sam przyjrzę się później
Lewis Kelsey
Wygląda na to, że zastępuje wpis __cxa_pure_virtual arobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/… zamiast Base :: f ()
Lewis Kelsey
1

Cóż, możesz także zainicjować wpis vtable, aby wskazywał na rzeczywistą funkcję "

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

Wydaje się intuicyjne, że wpis vtable można zdefiniować tak, aby wskazywał donikąd (0) lub do funkcji. Pozwolenie na określenie własnej wartości prawdopodobnie spowodowałoby, że wskazywałoby to na śmieci zamiast funkcji. Ale właśnie dlatego „= 0” jest dozwolone, a „= 1” nie. Podejrzewam, że Neil Butterworth ma rację, dlaczego w ogóle używa się „= 0”

Brian
źródło
1
Nawet ja miałem podobną opinię, ale ponieważ wielu zacytowało standardy i komentarze Bjarne'a na ten sam temat, mamy minimalne szanse na kłótnię :)
mukeshkumar