Załóżmy, że mam następujące dwa pliki, main.cpp
:W jaki sposób kompilator wie, który blok catch ma wykonać?
#include <iostream>
class A {};
void foo();
int main(void)
{
try {
foo();
}
catch(const A& e) {
std::cout << "Caught an A." << std::endl;
}
return 0;
}
i foo.cpp
:
class A {};
class B : public A {};
void foo()
{
B b;
throw b;
}
Teraz, kiedy mogę skompilować każdy z tych plików osobno, połączyć wynikowe pliki obiektów i uruchom otrzymany wykonywalny, otrzymuję oczekiwany wynik:
$ clang++ --std=c++14 -c main.cpp
$ clang++ --std=c++14 -c foo.cpp
$ clang++ --std=c++14 main.o foo.o
$ ./a.out
Caught an A.
I to jest straszne dla mojego umysłu! Klasa A
nie ma wirtualnych metod. Dlatego nie jest polimorficzny, a jego wystąpienia powinny zawierać informacje o typie w czasie wykonywania. Plik obiektowy main.o
jest nieświadomy tego, co jest rzucane, ponieważ faktyczne rzucanie odbywa się wewnątrz foo()
, którego treść jest zdefiniowana w oddzielnej jednostce kompilacji. Plik obiektowy foo.o
zawiera więcej informacji, ale jest równie nieświadomy jakichkolwiek instrukcji catch i oczekiwanych typów wychwyconych wyjątków.
W skrócie: Nie widzę, w jaki sposób oba pliki źródłowe zostały skompilowane osobno, a następnie połączone mogą wytworzyć powyższe dane wejściowe, nie dysponując informacjami o typie środowiska wykonawczego. Żaden z plików skompilowanych osobno nie powinien mieć wystarczających informacji, aby wziąć odpowiedni blok catch.
B jest podklasą A, dzięki czemu można zobaczyć na każdej instancji B z „soczewki” A. – freestyle
dlaczego jesteś przedefiniowanie 'klasy A'? – Raindrop7
Ponieważ kowariancji – arturx64