To pytanie jest zainspirowane komentarzami here.Czy zgodny z normą kod odrzucający kompilator zawierający downcast dynamic_cast od typu nie-polimorficznego?
Rozważmy następujący fragment kodu:
struct X {}; // no virtual members
struct Y : X {}; // may or may not have virtual members, doesn't matter
Y* func(X* x) { return dynamic_cast<Y*>(x); }
Kilka osób sugeruje, że ich kompilator byłoby odrzucić ciało func
.
Jednak wydaje mi się, że to, czy jest to określone przez Standard, zależy od wartości wykonawczej x
. Z sekcji 5.2.7 ([expr.dynamic.cast]
)
Wynikiem ekspresji
dynamic_cast<T>(v)
jest wynikiem konwersji ekspresjęv
wpisaćT
.T
będzie wskaźnikiem lub odniesieniem do pełnego typu klasy lub "wskaźnikiem do cvvoid
." Operator nie powinien odrzucać stałej.Jeśli
T
jest rodzajem wskaźnika,v
powinny być prvalue od wskaźnika ukończenia klasy rodzaj, a wynik jest prvalue typuT
. JeśliT
jest typem odniesienia o wartości l ,v
będzie lwartością pełnego typu klasy, a wynik jest lwartością typu określonego przezT
. JeśliT
jest typem odniesienia rvalue , to wyrażeniev
będzie wyrażeniem mającym pełny typ klasy, , a wynikiem jest wartość x typu określonego przezT
.Jeśli typ
v
jest taka sama jakT
, czy to jest taki sam jakT
wyjątkiem tego, że klasa typu obiekt wT
jest bardziej cv wykwalifikowany niż typ klasy obiektu wv
, wynik jestv
(w razie potrzeby przekonwertowane).Jeżeli wartość
v
jest wartość null pointer w przypadku wskaźnika, wynik jest wartość null pointer typuT
.Jeśli T jest "wskaźnik do CV1
B
" iv
ma typ „wskaźnik do CV2D
" tak, żeB
to klasa bazowaD
, wynik jest wskaźnik unikalnemuB
podobiekt obiektuD
wskazany przezv
. Podobnie, T „definicja CV1B
” iv
ma typ CV2D
tak, żeB
jest klasa podstawyD
wynik jest unikalnyB
podobiekt obiektuD
określoną przezv
. Rezultatem jest wartość l, jeśliT
jest wartością odniesienia o wartości l lub wartością x, jeśliT
jest referencją rVue. W obu wskaźnik i odniesienia przypadkach program jest źle sformułowane jeśli CV2 ma większą CV kwalifikacje niż CV1 czyB
jest niedostępne lub niejednoznaczne klasa bazowaD
.W przeciwnym razie,
v
będzie wskaźnikiem lub lwartością typu polimorficznego.Jeśli
T
jest „wskaźnik do cvvoid
”, wtedy wynik jest wskaźnikiem do najbardziej pochodzącego obiektu wskazywanego przezv
. W przeciwnym razie sprawdzanie czasu wykonania zostanie zastosowane, aby zobaczyć , jeśli obiekt wskazany lub określony przezv
może zostać przekonwertowany na typ wskazany lub określony przezT
. Najbardziej wyprowadzony obiekt wskazany jako lub określony przezv
może zawierać inneB
obiekty jako klasy podstawowe, ale są one ignorowane.Jeśli
C
jest typem klasy, do którejT
punktów lub odsyła sprawdzenie czasu wykonywania logicznie wykonywany jako następująco:
Jeżeli w najbardziej obiektu pochodzącego wskazał (o którym mowa) do o
v
,v
punktów (obliczono) do klasypublic
bazowej podobiektu zC
obiektu, a jeżeli tylko jeden przedmiot typuC
pochodzi od podobiektu wskazał (o którym mowa), aby przezv
the punktów wyniku (dotyczy) do tego obiektuC
.przeciwnym razie, jeśli
v
punktów (obliczono) do klasypublic
bazowej podobiektu przedmiotu najbardziej pochodnej, i rodzaju przedmiotu najbardziej pochodzącego posiada klasę zasady, typuC
, jednoznacznej ipublic
, punkty wynikowe (odwołanie) do podobiektu obiektu pochodnego.W przeciwnym razie sprawdzanie w czasie pracy nie powiedzie się.
Wartość nieudanej oddanych do typu wskaźnika jest wartość zerowa wskaźnik wymaganego typu wynikowego. Nieudany rzut do rzutów typu
std::bad_cast
.
Sposób czytam ten wymóg typu polimorficznych zastosowanie jedynie wtedy, gdy żaden z powyższych warunków nie jest spełniony, a jeden z tych warunków zależy od wartości wykonawczego.
Oczywiście w kilku przypadkach kompilator może pozytywnie określić, że dane wejściowe nie mogą mieć poprawnej wartości NULL (na przykład, gdy jest to wskaźnik this
), ale nadal uważam, że kompilator nie może odrzucić kodu, chyba że może ustalić, że oświadczenie zostanie osiągnięte (zwykle jest to pytanie dotyczące czasu pracy).
Diagnostyka ostrzegawcza jest oczywiście tutaj wartościowa, ale czy jest ona zgodna ze standardem, aby kompilator odrzucił ten kod z błędem?
6. jest prawie kryształowo czysty, prawda? Zwłaszcza, że wszystko powyżej nie ma zastosowania. –
@AlexandreC .: Jak można stwierdzić, z wyświetlonego kodu, że (4) nie ma zastosowania? Zwróć uwagę, że jest to "wartość pustego wskaźnika *", która może nie być znana do czasu wykonania, a nie "wskaźnik zerowy * literał *" lub "stała zerowa * stała *". –
(Nie jestem downvoter). Rzeczywiście, czytałem "zerowy wskaźnik" dosłowny "" lub coś podobnego. Czy próbujesz sugerować, że kompilator powinien przetłumaczyć rzutowanie dynamiczne na "assert (! V)" lub coś podobnego w przypadku nie polimorficznym? –