Udostępnij za pośrednictwem


Notacja rzutowania i przedstawienie operacji safe_cast<>

Notacja cast zmienił się z rozszerzeń zarządzanych języka C++ do Visual C++.

Modyfikowanie istniejącej struktury jest inne i trudniejsze doświadczenie niż rzemieślniczy początkowego strukturze.Istnieje mniejsza liczba stopni swobody, a roztwór dąży do kompromisu między idealne restrukturyzacji i co to jest możliwe, biorąc pod uwagę istniejących współzależności strukturalnych.

Rozszerzenie języka jest inny przykład.Powrót w początku lat dziewięćdziesiątych jako Object-orientacja programowania stał się ważnym paradygmat, potrzebę typ palety spuszczonymi obiektu portowego w języku C++ został naciśnięcie kombinacji klawiszy.Rzutowanie w dół jest konwersja jawna użytkownika wskaźnik klasa bazowa lub odwołanie do wskaźnika lub odwołanie klasy pochodnej.Rzutowanie w dół wymaga jawnego oddanych.Dlatego, że rzeczywisty typ wskaźnika klasy podstawowej jest aspektem środowiska wykonawczego; Kompilator zatem nie może sprawdzić go.Lub do parafrazując, spuszczonymi obiektu portowego, podobnie jak wywołanie funkcji wirtualnych wymaga pewnych form dynamiczne rozdzielczość.Podnosi dwa pytania:

  • Dlaczego spuszczonymi być konieczne w modelu obiektowego?Mechanizm funkcji wirtualnych nie wystarcza?Oznacza to, dlaczego nie można jednym twierdzą, że jakąkolwiek potrzebę spuszczonymi (lub cast jakiejkolwiek) jest błąd projektu?

  • Dlaczego wsparcie spuszczonymi się problem w języku C++?Mimo wszystko, nie jest to problem w obiektowych języków, takich jak Smalltalk (lub później, Java i C#)?Co to jest o C++, który ułatwia obsługę spuszczonymi obiektu portowego trudne?

Funkcji wirtualnych reprezentuje wspólne algorytmem zależne od typu do rodziny typów. (Firma Microsoft nie rozważa interfejsy, które nie są obsługiwane w ISO C++, ale są dostępne w programowaniu CLR i które reprezentują interesującą alternatywą projektu).Projekt danej rodziny jest zazwyczaj reprezentowany przez hierarchia klas, w których jest to abstrakcyjna klasa podstawowa deklarowania wspólny interfejs (funkcje wirtualnych) oraz zestaw konkretnych klas pochodnych, które stanowią rzeczywiste typy rodziny w domenie aplikacji.

A Light hierarchii w domenie aplikacji komputera generowane zdjęć (CGI), na przykład, będzie miał wspólnych atrybutów takich jak color, intensity, position, on, off, i tak dalej.Kilku świateł, można kontrolować za pomocą wspólny interfejs bez martwienia się, czy konkretnego światełka jest światłem, kierunkowe światło, światło-kierunkowe (zespoły słońca) lub może być wrota światło.W tym przypadku rzutowanie w dół z określonym typem światła do wykonywania jego interfejs wirtualny nie jest konieczne.W środowisku produkcyjnym Jednakże, prędkość jest niezbędna.Jeden może być spuszczonymi i jawnie wywołać każdą z tych metod, jeśli w ten sposób inline wykonywania wywołań można wykonać zamiast przy użyciu mechanizmu wirtualnego.

Tak jeden powód, aby spuszczonymi w języku C++ jest wyłączyć mechanizm wirtualnego w zamian za istotny przyrost wydajności w czasie wykonywania. (Należy zauważyć, że w automatyzacji Optymalizacja ręczne jest aktywnym obszarem badań.Jednakże, jest trudniejsze do rozwiązania niż zastąpienie jawne użycie register lub inline słowa kluczowego.)

Drugi powód do spuszczonymi wypadnie z podwójną naturę polimorfizmu.Jeden sposób myślenia polimorfizmu jest jest podzielony na parę pasywnych i dynamiczne formularze.

Wywołania wirtualnej (i spuszczonymi obiektu portowego) reprezentuje dynamiczne zastosowań polimorfizmu: jeden wykonuje akcję na podstawie rzeczywistej typu wskaźnik klasy bazowej w tym konkretnym przypadku wykonywanie programu.

Przypisywanie obiektu klasy pochodne do jej wskaźnik klasy podstawowej, jednak jest bierna polimorfizmu; Polimorfizm używa jako mechanizmu transportowego.To jest głównym zastosowaniem Object, na przykład w programowaniu wstępnie rodzajowy CLR.Gdy używana biernie, wskaźnik klasy podstawowej wybrany dla transportu i składowania zazwyczaj oferuje interfejs, który jest zbyt abstrakcyjna.Object, na przykład zawiera około pięć metod za pośrednictwem jej interfejsu; wszelkie dokładniejsze zachowanie wymaga wyraźnego spuszczonymi.Na przykład jeśli chcemy dopasować kąt naszych spotlight lub jego stopy od spadku, będziemy musieli spuszczonymi jawnie.Interfejs wirtualny w obrębie rodziny z podtypów praktycznie nie może być nadzbiorem wszystkich możliwych metod wiele podrzędnych i tak spuszczonymi obiektu portowego, zawsze będą potrzebne w ramach zorientowany obiektowo język.

Jeżeli bezpiecznym spuszczonymi obiektu portowego jest konieczne w zorientowany obiektowo język, a następnie Dlaczego C++ tak długo Aby dodać jeden?Problem jest w sposób udostępnić informacje dotyczące typów w czasie wykonywania wskaźnik.W przypadku funkcji wirtualnych informacje o wykonaniu ustawiono w dwóch częściach przez kompilator:

  • Obiekt klasy zawiera element członkowski wskaźnik dodatkowej tabeli wirtualnej (albo na początku lub na końcu obiektu klasy; to ma w sobie ciekawą historię) że odnosi się do odpowiedniej tabeli wirtualnych.Na przykład obiekt spotlight adresy tabeli wirtualnej spotlight, kierunkowe światło kierunkowe światło tabeli wirtualnej i tak dalej

  • Każda metoda wirtualna ma skojarzony stałej gniazdo w tabeli i rzeczywistego wystąpienia do wywołania jest reprezentowana przez adres przechowywany wewnątrz tabeli.Na przykład, wirtualne Light destruktora mogą być skojarzone z gniazdem 0, Color z slot 1 i tak dalej.Jest to efektywne, jeżeli nieelastyczne strategii, ponieważ skonfigurowano w czasie kompilacji i reprezentuje minimalnym nakładzie kosztów.

Problem, jest następnie, sposobów udostępniania informacji typu kursor bez zmiany rozmiaru wskaźników C++, przez dodanie drugiego adresu lub dodając bezpośrednio jakiś typ kodowania.Nie byłoby to możliwe do zaakceptowania tych programistów (i programy) które podjęły decyzję o paradygmatu zorientowanym obiektowo — który był jeszcze dominujący użytkowników.Inną możliwością było wprowadzenie specjalnych wskaźnika dla typów polimorficzne klas, ale to byłoby mylące i utrudnić wymieszać między dwoma, szczególnie co do spraw arytmetyki.Nie byłoby możliwe do zaakceptowania Obsługa tabeli wykonywania, który kojarzy każdy wskaźnik z jej obecnie skojarzony typ i dynamiczne aktualizowanie go.

Problem jest następnie parę społeczności użytkowników, które mają różne, ale uzasadnione aspiracje programowania.Roztwór musi być kompromis między dwoma Wspólnotami, dzięki czemu każdy nie tylko ich wdychania, ale zdolność do współpracy.Oznacza to, że rozwiązania oferowane przez jedną ze stron mogą być niewykonalne i roztwór ostatecznie implementowane za mniej niż doskonałe.Rzeczywistej rozdzielczości obraca się wokół definicji klasy polimorficzne: polimorficzne klas jest taką, która zawiera funkcję wirtualną.Klasa polimorficzna obsługuje dynamiczne typ palety spuszczonymi.Rozwiązuje problem maintain-wskaźnik jako adres, ponieważ zawiera wszystkie klasy polimorficzna tego członka dodatkowy wskaźnik ich skojarzona Tabela wirtualnych.W związku z tym, skojarzonego typu informacji, mogą być przechowywane w tabeli wirtualnej rozwiniętej struktury.Koszt typ palety spuszczonymi (prawie) jest zlokalizowany dla użytkowników instrumentu.

Następny problem z typu palety spuszczonymi była jego składni.Ponieważ rzutu, pierwotny wniosek do Komitetu ISO C++ używane składni cast ozdób, jak w poniższym przykładzie:

spot = ( SpotLight* ) plight;

ale została odrzucona przez Komitet, ponieważ go nie pozwalają użytkownikowi kontrolować koszt oddanych.Jeśli dynamiczny typ palety spuszczonymi ma taką samą składnię jako niebezpiecznego wcześniej, ale statyczne notacji cast, to staje się zastąpienie, a użytkownik nie ma możliwości Pomiń obciążenie runtime, gdy jest niepotrzebne i być może zbyt kosztowna.

Ogólnie rzecz biorąc w języku C++, zawsze istnieje mechanizm, za pomocą której wyłączyć funkcje obsługiwane przez kompilator.Na przykład, będziemy mogli wyłączyć mechanizm wirtualnego za pomocą operatora zakresu klasy (Box::rotate(angle)) lub przez wywołanie metody wirtualnych za pośrednictwem obiektu klasy (zamiast wskaźnika lub odniesienie do tej klasy).Tłumienia to ostatnie nie jest wymagane przez język, ale jest jakość wykonania wydania, podobne do tłumienia budowy tymczasowego w deklaracji formularza:

// compilers are free to optimize away the temporary
X x = X::X( 10 );

Więc propozycja została podjęta już do dalszego rozpatrzenia i kilka zapisów alternatywne zostały uznane i sprowadzony do Komitetu był formularza (?type), który wskazano jego nieokreślony — czyli dynamiczny charakter.Możliwość przełączania między dwoma formularzami — statyczne lub dynamiczne — to dało użytkownika, ale nikt nie był zbyt zadowolony z nim.Tak było, wróć do rysunku.Notacja trzeciego i udane jest teraz standard dynamic_cast<type>, który został uogólniony z zestawem czterech Obsada nowego stylu notacji.

W języku C++ ISO dynamic_cast zwraca 0 gdy stosowany do typu wskaźnik niewłaściwe i generuje std::bad_cast wyjątek po zastosowaniu do typu odwołania.W rozszerzenia zarządzane dla języka C++ stosowanie dynamic_cast do typu zarządzanego odniesienia (ze względu na jego reprezentację wskaźnik) zawsze zwracana 0.__try_cast<type>został wprowadzony jako analogowego, z wyjątkiem rzucanie wariant dynamic_cast, z tym wyjątkiem, że to wyrzuca System::InvalidCastException Jeśli obsady nie powiedzie się.

public __gc class ItemVerb;
public __gc class ItemVerbCollection {
public:
   ItemVerb *EnsureVerbArray() [] {
      return __try_cast<ItemVerb *[]>
         (verbList->ToArray(__typeof(ItemVerb *)));
   }
};

W nowych składni __try_cast zostało przepracowane jako safe_cast.Oto fragment kodu w samym w nowe elementy składni:

public ref class ItemVerb;
public ref class ItemVerbCollection {
public:
   array<ItemVerb^>^ EnsureVerbArray() {
      return safe_cast<array<ItemVerb^>^>
         ( verbList->ToArray( ItemVerb::typeid ));
   }
};

W świecie zarządzanych jest ważne, aby umożliwić sprawdzalne kodu ograniczając możliwości programistów do oddania między typami w sposób, który pozostawić kod jest niemożliwy.To jest kluczowym aspektem dynamicznego paradygmatu programowania reprezentowane przez nowe elementy składni.Z tego powodu wystąpienia poświaty starym stylu są przekształcenie wewnętrznie jako wykonywania prezentacji, tak że, na przykład:

// internally recast into the 
// equivalent safe_cast expression above
( array<ItemVerb^>^ ) verbList->ToArray( ItemVerb::typeid ); 

Z drugiej strony ponieważ polimorfizm zapewnia zarówno aktywny, jak i trybu pasywnego, czasami jest konieczne przeprowadzenie spuszczonymi tak, aby uzyskać dostęp do interfejsu API-virtual podtypu.Taka sytuacja może wystąpić, na przykład z element(y) członkowski(e) klasy, które chcą adres każdym wpisz w ramach hierarchii (polimorfizmu pasywny jako mechanizm transportu), ale dla którego znany jest rzeczywiste wystąpienie w kontekście określonego programu.W tym przypadku posiadające wyboru wykonywania oddanych może być niedopuszczalne obciążenia.Jeżeli nowe elementy składni ma służyć jako systemów zarządzanych języka programowania, musi ono zapewnić pewne środki pozwalające w czasie kompilacji (czyli statyczne) spuszczonymi.Dlatego stosowanie static_cast notacji może pozostawać w czasie kompilacji spuszczonymi:

// ok: cast performed at compile-time. 
// No run-time check for type correctness
static_cast< array<ItemVerb^>^>(verbList->ToArray(ItemVerb::typeid));

Problem jest, że ma gwarancji, że programista robi static_cast jest poprawny i dobrych intencji; oznacza to nie istnieje żaden sposób zmusić kodu zarządzanego, aby były weryfikowalne.Jest to bardziej naglące zaniepokojenie pod paradygmat dynamiczny program niż w trybie macierzystym, ale nie są wystarczające w ramach systemu programowania język, aby uniemożliwić użytkownikowi możliwość przełączania między statyczne i wykonywania oddanych.

Ma wydajność pułapki i niedogodności w nowe elementy składni, jednak.W programowaniu macierzystego nie ma żadnej różnicy w wydajności między notacji cast starym stylu i nowy styl static_cast notacji.Ale w nowe elementy składni, jest znacznie droższe niż użycie nowego stylu notacji cast tradycyjną static_cast notacji.Powodem jest to, że kompilator wewnętrznie przekształca użycie notacji stary styl do wyboru wykonywania, która zgłasza wyjątek.Ponadto, również zmiany profilu wykonywanie kodu, ponieważ powoduje on nieprzechwycony wyjątek dostosowanie w dół aplikacji — być może go w rozsądny sposób, ale ten sam błąd nie może powodować tego wyjątku, jeśli static_cast notacji były używane.Może być jednym twierdzą, pomoże prod użytkowników do przy użyciu notacji nowego stylu.Ale tylko wtedy, gdy nie jest on; w przeciwnym wypadku spowoduje to programy używające notacji stary styl do działać znacznie wolniej, bez widocznych zrozumienia Dlaczego, podobne do następujących pułapek programista C:

// pitfall # 1: 
// initialization can remove a temporary class object, 
// assignment cannot
Matrix m;
m = another_matrix;

// pitfall # 2: declaration of class objects far from their use
Matrix m( 2000, 2000 ), n( 2000, 2000 );
if ( ! mumble ) return;

Zobacz też

Informacje

C styl poświaty z/CLR

safe_cast

Koncepcje

Ogólne zmiany w języku (C++/CLI)