Co to jest wczesne i późne wiązanie?
On 18 listopada, 2020 by adminCiągle słyszę o wczesnym i późnym wiązaniu, ale nie rozumiem, czym one są. Znalazłem następujące wyjaśnienie, którego nie rozumiem:
Wczesne wiązanie odnosi się do przypisywania wartości do zmiennych w czasie projektowania, podczas gdy późne wiązanie odnosi się do przypisywania wartości do zmiennych w czasie wykonywania.
Czy ktoś mógłby zdefiniować dwa typy powiązań i porównać je?
Komentarze
- czas kompilacji a środowisko wykonawcze.
- Oto dobra lektura na ten temat: en.wikibooks.org/ wiki / Introduction_to_Programming_Languages / …
Odpowiedź
Istnieją dwa główne pojęcia związane z zamieszaniem: wiązanie i ładowanie. Jest to powiązane z koncepcją DataBinding, która gdzieś pośrodku często robi jedno i drugie. Po rozważeniu tego, dodam jeszcze jedną koncepcję, aby zakończyć trifectę, wysyłkę.
Typy
Późne wiązanie : typ jest nieznany , dopóki zmienna nie zostanie przetestowana w czasie wykonywania; zwykle poprzez przydział, ale są inne sposoby na zmuszenie typu; języki z typami dynamicznymi nazywają to funkcją podstawową, ale wiele języków z typami statycznymi ma pewną metodę osiągnięcia późnego wiązania
Implementowane często przy użyciu [specjalnych] typów dynamicznych, introspekcji / refleksji, flag i opcji kompilatora lub poprzez metody wirtualne poprzez wypożyczanie i przedłużanie dynamicznej wysyłki
Early Binding : typ jest znany przed wykonaniem zmiennej w czasie wykonywania, zwykle za pomocą statycznych, deklaratywnych środków
Implementowane często przy użyciu standardowych typów pierwotnych
Funkcje
Wysyłka statyczna : znana, określona funkcja lub podprogram w czasie kompilacji; jest jednoznaczny i dopasowany do podpisu
Zaimplementowano jako funkcje statyczne; żadna metoda nie może mieć tego samego podpisu
Dynamiczne wysyłanie : nie jest to określona funkcja lub podprocedura w czasie kompilacji; określone przez kontekst podczas wykonywania. Istnieją dwa różne podejścia do „dynamicznego wysyłania”, różniące się tym, jakie informacje kontekstowe są używane do wyboru odpowiedniej implementacji funkcji.
W pojedynczym [ dynamicznym ] wysyłka , tylko typ instancji jest używany do określenia odpowiedniej implementacji funkcji. W językach z typami statycznymi w praktyce oznacza to, że typ instancji decyduje, która implementacja metody jest używana, niezależnie od typu odwołania wskazanego podczas deklarowania / przypisywania zmiennej. Ponieważ tylko jeden typ – typ instancji obiektu – jest używany do wnioskowania o odpowiedniej implementacji, podejście to nazywa się „pojedynczą wysyłką”.
Istnieje również wielokrotne [ dynamiczne ] wysyłka , gdzie typy parametrów wejściowych również pomagają określić, którą implementację funkcji należy wywołać. Ponieważ wiele typów – zarówno typ wystąpienia , jak i typ (y) parametrów – wpływ która implementacja metody jest wybrana, podejście to nazywa się „wysyłaniem wielokrotnym”.
Zaimplementowane jako funkcje wirtualne lub abstrakcyjne; inne wskazówki obejmują metody przesłonięte, ukryte lub ukryte.
Uwaga: To, czy przeciążanie metod wiąże się z dynamicznym wysyłaniem, zależy od języka. Na przykład w Javie przeciążone metody są wysyłane statycznie.
Wartości
Leniwe ładowanie : strategia inicjalizacji obiektu, która odracza przypisanie wartości do czasu, gdy będzie to potrzebne ; pozwala obiektowi być w zasadniczo ważnym, ale świadomie niekompletnym stanie i czekać, aż dane będą potrzebne przed ich załadowaniem; często uznawane za szczególnie przydatne do ładowania dużych zestawów danych lub oczekiwania na zasoby zewnętrzne
Często implementowane przez celowe nie ładowanie kolekcji lub listy do obiektu złożonego podczas wywołań konstruktora lub inicjalizacji, dopóki jakiś podrzędny wywołujący nie poprosi o wyświetlenie zawartości ta kolekcja (np. get_value_at, get_all_as itp.).Odmiany obejmują ładowanie metainformacji o kolekcji (takich jak rozmiar lub klucze), ale pomijanie rzeczywistych danych; zapewnia także mechanizm dla niektórych środowisk wykonawczych, aby zapewnić programistom dość bezpieczny i wydajny schemat implementacji singletona
Zachłanne ładowanie : strategia inicjalizacji obiektu, która natychmiast wykonuje wszystkie przypisania wartości w celu uzyskania wszystkich danych potrzebnych do uzupełnienia przed uznaniem siebie za prawidłowy.
Często wdrażany dostarczanie obiektom złożonym wszystkich znanych danych tak szybko, jak to możliwe, na przykład podczas wywołania konstruktora lub inicjalizacji
Wiązanie danych : często wiąże się z utworzeniem aktywnego łącza lub mapy między dwoma zgodnymi strumieniami informacji , tak aby zmiany jednego z nich były odzwierciedlane z powrotem w drugim i odwrotnie; aby być kompatybilnymi, często muszą mieć wspólny typ bazowy lub interfejs
Wdrażane często jako próba zapewnienia czystej, spójnej synchronizacji między różnymi aspektami aplikacji (np. itp.) i mówi o pojęciach takich jak źródło i cel, punkty końcowe, bind / unbind, update i zdarzenia, takie jak on_bind, on_property_change, on_explicit, on_out_of_scope
EDYTUJ UWAGA: Ostatnia ważna zmiana w celu dostarczenia opisu przykładów tego, jak często się to zdarza. Poszczególne przykłady kodu zależą całkowicie od implementacji / środowiska wykonawczego / platformy
Komentarze
- Ta odpowiedź wydaje się zbyt specyficzna dla języków zorientowanych obiektowo.
- @Jack Nie ' nie czuję się w ten sposób, myślę, że jest to doskonała, która obejmuje wiele aspektów.
Odpowiedź
Wszystko, o czym zdecyduje kompilator podczas kompilacji, można odnieść do WCZESNEGO / CZASU KOMPILACJI Wiązanie i wszystko, co ma zostać rozstrzygnięte w RUNTIME , nazywa się LATE / RUNTIME bind.
Na przykład
Metoda Przeciążanie i metoda Zastępowanie .
1 ) W Przeciążaniu metod wywołania metod do metod ar Decyduje kompilator w tym sensie, że o tym, która funkcja zostanie wywołana, decyduje twój kompilator w czasie kompilacji. Stąd WCZESNE WIĄZANIE .
2) W przypadku metody Overriding, w RUNTIME decyduje się, która metoda jest zostanie wezwany. Jest więc oznaczane jako PÓŹNE WIĄZANIE .
Postaraliśmy się, aby było proste i łatwe do uzyskania. Mam nadzieję, że to pomoże.
Odpowiedź
Późne wiązanie ma miejsce, gdy zachowanie jest oceniane w czasie wykonywania. Jest to konieczne, gdy naprawdę chcesz określić, jak postępować w oparciu o informacje, które masz tylko wtedy, gdy program jest uruchomiony. Moim zdaniem najlepszym przykładem jest mechanizm funkcji wirtualnych, szczególnie w C ++.
class A { public: void f() {} virtual void g() {} }; class B : public A { void f() {} virtual void g() {} }; int main() { A* a = new B; a->f(); a->g(); }
W tym przykładzie a->f()
faktycznie wywoła void A::f()
, ponieważ jest wcześnie (lub statycznie ), więc program w czasie wykonywania myśli , że jest to tylko wskaźnik do zmiennej typu A
, podczas gdy a->g()
faktycznie wywoła void B::g()
, ponieważ kompilator widząc, że g()
jest wirtualny, wstrzykuje kod w celu wyszukania adresu odpowiedniej funkcji do wywołania w czasie wykonywania.
Komentarze
- ” Środowisko wykonawcze „? Ty ' mówisz o C ++. C ++ kompiluje się bezpośrednio do kodu maszynowego, nie ' nie potrzebujesz środowiska wykonawczego do rozwiązania metody wirtualne.
- @tdammers C ++ faktycznie potrzebuje biblioteki wykonawczej, ale nie do wywołań wirtualnych. Jeśli uważnie przeczytasz, ' zauważysz, że ta odpowiedź mówi, że kompilator ” wstrzykuje kod w celu wyszukania adresu prawidłowej funkcji [ …] w czasie wykonania „.
- No cóż, ale ten kod ” wyszukanie adresu prawidłowej funkcji ” jest w zasadzie po prostu niezależnym od typu dwustopniowym wyłuskiwaniem wskaźnika, po którym następuje wywołanie funkcji. Nie ma ” myślenia „; jedynym powodem, dla którego działa niezawodnie jest to, że kompilator sprawdza typ w czasie kompilacji ; w czasie wykonywania wygenerowany kod ufa kompilatorowi, że wykonał zadanie domowe dotyczące sprawdzania typu. Jeśli używasz niebezpiecznych rzutów (np.Rzutowania wskaźnika w stylu C), możesz legalnie traktować obiekty C ++ jako obiekty niewłaściwej klasy, ale ich vtables zostanie całkowicie pomieszane, a kod po prostu się zepsuje.
- @tdammers Starałem się trzymać z daleka od tego rodzaju odpowiedzi, ponieważ ' jest szczegółem implementacji kompilatorów, co może, ale nie musi, być prawdą dla jakiegoś ezoterycznego kompilatora. Liczy się koncepcja.
- @tdammers A przez ” czas wykonania ” mam na myśli ” program w czasie wykonywania „. Oczywiście C ++ nie jest ' t zarządzany. Ale ponieważ pokazałeś mi, że może to powodować zamieszanie, ' m zmieniam to na pełne brzmienie.
Odpowiedź
Jeśli znasz wskaźniki do funkcji, to byłby to przykład. Można powiedzieć, że zdefiniowane funkcje są wczesnym wiązaniem. podczas gdy jeśli używasz wskaźników funkcji, jego późne Binding.
int add(int x,int y) { return x+y; } int sub(int x,int y) { return x-y; } int main() { //get user choice int(*fp)(int,int); //if add fp=add; //else if sub fp=sub; cout<<fp(2,2); }
tutaj funkcje add i sub są funkcjami (ich adres jest powiązany z łącznikiem czasu kompilacji)
ale wskaźnik funkcji jest późny wiązanie fp może wywołać add lub sub w zależności od wyboru użytkownika [w czasie wykonywania].
Odpowiedź
Tylko wczesne i późne wiązanie ma sens w kontekście typów, a nie w sposobie, w jaki je opisujesz. Prawie wszystkie współczesne języki są wpisywane w tym sensie, że wszystkie wartości mają ustalone typy. Różnica pojawia się, gdy spojrzymy na języki dynamicznie i statycznie typowane. W językach z typami dynamicznymi zmienne nie mają typów, więc mogą odnosić się do wartości dowolnego typu, a to oznacza, że kiedy wywołujesz metodę na obiekcie, do którego odwołuje się jakaś zmienna, jedynym sposobem określenia, czy to wywołanie jest prawidłowe poszukaj w klasie obiektu i zobacz, czy ta metoda rzeczywiście istnieje. Pozwala to na kilka fajnych rzeczy, takich jak dodawanie nowych metod do klas w czasie wykonywania, ponieważ faktyczne wyszukiwanie metod jest odroczone do ostatniej chwili. Większość ludzi nazywa ten stan sprawy z późnym wiązaniem.
W języku z typami statycznymi zmienne mają typy i raz zadeklarowane nie mogą odnosić się do żadnej wartości, która nie jest tego samego typu. Nie jest to do końca prawdą, ale załóżmy to na razie. Teraz, jeśli wiesz, że zmienna będzie zawsze odnosić się tylko do wartości określonego typu, nie ma powodu, aby dowiedzieć się, czy wywołanie metody jest prawidłowe, czy nie w czasie wykonywania, ponieważ możesz określić ważność, zanim kod zostanie kiedykolwiek uruchomiony. Nazywa się to wczesnym wiązaniem.
Przykład pokazujący późne wiązanie w Rubim:
a = 1 # a is an integer at this point a.succ # asking for its successor is valid class A def method_a # some code end end a = A.new a.method_a # this is also valid a.succ # this is not valid class A # we can re-open the class and add a method def succ # some more code end end a.succ # now this is valid
Powyższa sekwencja działań nie jest możliwe w języku takim jak Java, gdzie wszystkie typy są ustalane w czasie wykonywania.
Odpowiedź
Zamiast podawać akademicką definicję I spróbuje pokazać Ci niektóre różnice na prawdziwym przykładzie z użyciem VBA:
Wczesne wiązanie:
Dim x As FileSystemObject Set x = New FileSystemObject Debug.Print x.GetSpecialFolder(0)
Wymaga to ustawienia odwołania do składnika „Microsoft Scripting Runtime” w czasie projektowania . Ma tę zaletę, że w przypadku wystąpienia literówki w FileSystemObject
lub nazwach metod, takich jak GetSpecialFolder
, już podczas kompilacji pojawia się błąd. / p>
Późne wiązanie
Dim x As Object Set x = CreateObject("Scripting.FileSystemObject") Debug.Print x.GetSpecialFolder(0)
Nie wymaga to wcześniejszego ustawienia odniesienia, utworzenie i typ instancji determinacja nastąpi po prostu w czasie wykonywania. Kompilator wygrał „t narzekanie w czasie kompilacji, gdy spróbujesz wywołać nieistniejącą metodę x
, spowoduje to błąd w czasie wykonywania tylko wtedy, gdy wykonywana jest określona linia .
Wadą późnego wiązania jest to, że nie ma tu żadnego silnego sprawdzania typu. Ale to również zaleta – powiedzmy, że masz komponent, w którym istnieje kilka wersji, a każda nowsza wersja zapewnia dodatkowe funkcje. (Przykładem rzeczywistym są komponenty MS Office, takie jak interfejs COM Excela). piszesz kod, który działa razem ze wszystkimi wersjami – możesz najpierw określić konkretną wersję komponentu, a jeśli stwierdzisz, że masz tylko starszą wersję, unikaj wywołań funkcji, które nie działają z tą wersją.
Odpowiedź
Prawdopodobnie najczęstszym przykładem późnego wiązania jest rozwiązywanie internetowych adresów URL. Obsługuje systemy dynamiczne i duże systemy bez próby łączenia i wiązania każdej witryny na świecie, zanim będzie można dotrzeć do jakiejkolwiek, ale z drugiej strony powoduje pewne obciążenie (wyszukiwanie DNS, znacznie mniej routing IP) w czasie wykonywania.
W tym świetle większość odmian powiązań w środowiskach językowych jest mniej więcej wczesna, w czasie kompilacji lub w czasie łączenia.
Każdy rodzaj ma swoje koszty i korzyści.
Komentarze
- Czy możesz umieścić odniesienie do tej definicji wiązania?Nie słyszałem o rozwiązywaniu adresów internetowych jako ” wiążących „, chociaż skoro wiązanie jest aktem rozwiązywania nazw, przypuszczam, że ktoś się spierał że koncepcję wczesnego / późnego wiązania można zastosować do tłumaczenia URI na adresy internetowe. Nie jest to jednak powszechna interpretacja, a koncepcja wczesnego / późnego wiązania pochodzi sprzed czasów, gdy komputery były zwykle połączone z Internetem.
Dodaj komentarz