2017-09-15 14 views
13

Czytałem w wielu miejscach (na przykład here) o ludziach otrzymujących "czystą wirtualną metodę zwaną" błąd i awarię programu w runtime. This answer mówi, żeW jakich warunkach generowany jest czysty kod wirtualny?

Większość kompilatorów przypisuje takie pozycje vtable do kodu pośredniczącego, który emituje błąd przed przerwaniem programu.

i this one nawet mówi, że Itanium ABI określa, co to jest skrót.

Problem polega na tym, że wszystkie moje próby zobaczenia tego zachowania w działaniu przechwytuje kompilator (GCC 6.4.1) pod czas kompilacji jako niezdefiniowane odniesienia. Na przykład, podczas wywoływania czystą funkcję wirtualną z konstruktora z klasy abstrakcyjnej, pojawia się ostrzeżenie

pure virtual ‘virtual int X::f()’ called from constructor

ale w tym samym czasie po prostu brak kodu w ogóle jest generowany dla X::f() więc to następuje

undefined reference to 'X::f()'

z łącznikiem i kompilacja zakończy się niepowodzeniem. Wydaje się to całkiem niezastąpionym sposobem zapobiegania błędowi w czasie wykonywania. W jakiej sytuacji mój kompilator rzeczywiście musiałby wygenerować wyżej wymieniony kod pośredniczący? Czy jest wystarczająco inteligentny, aby wystarczająco wcześnie wykryć wszystkie możliwe sytuacje patologiczne?

+3

To nigdy nie wymagane do wygenerowania niedopałek. Wywołanie czystej wirtualnej metody jest niezdefiniowanym zachowaniem. Niektóre kompilatory wykorzystują permisywny charakter nieokreślonego zachowania, aby zapewnić go jako grzeczność. –

Odpowiedz

10

Zazwyczaj będzie on wywoływany pośrednio z poziomu konstruktora. Poniżej minimalny przykład:

#include <iostream> 

struct X { 
    virtual void foo() = 0; 
    void bar() { foo(); } 
    X() { bar(); std::cout << "X"; } 
}; 

struct Y : X { 
    void foo() override {} 
}; 


int main() { 
    Y y; 
    return 0; 
} 

Kompilator zobowiązany jest do wiązania się z połączenia statycznie, jeżeli okaże się wewnątrz c'tor bezpośrednio (a tym samym może wytwarzać użyteczny komunikat do czystej funkcji wirtualnej). Ale gdy połączenie jest pośrednie, z innego elementu, musi być dynamicznie wysyłane.

Oczywiście, część Y nie została jeszcze zbudowana podczas budowy X, więc cała rzecz zapada się w płomień nieokreślonego zachowania.

Live example - With the stub at work

+0

Jestem zaskoczony, że kompilator nie narzeka na wywołanie metody wirtualnej od konstruktora. – Steve

+3

@Steve - Ale nie wywołujemy funkcji wirtualnej od c'tor. Nie bezpośrednio. Trudno jest sprawdzić, czy nazywamy to pośrednio. – StoryTeller

+0

Ah. To ma wiele sensu. Dzięki za wytłumaczenie. – Steve

Powiązane problemy