Дозвольте навести вам приклад відмінностей, оскільки вони НЕ однакові. Так, динамічне відправлення дозволяє вибрати правильний метод, коли ви посилаєтесь на об'єкт суперкласом, але ця магія дуже специфічна для цієї ієрархії класів, і вам потрібно зробити деякі оголошення в базовому класі, щоб він працював (абстрактні методи заповнити vtables, оскільки індекс методу в таблиці не може змінюватися між конкретними типами). Отже, ви можете викликати методи в Tabby і Lion і Tiger за допомогою загального вказівника Cat і навіть мати масиви Кішок, наповнених Lions and Tigers and Tabbys. Він знає, на які індекси посилаються ці методи у vtable об'єкта під час компіляції (статичне / раннє прив'язка), навіть незважаючи на те, що метод обраний під час виконання (динамічне відправлення).
Тепер давайте реалізуємо масив, який містить Левів, Тигрів та Ведмедів! ((О мій!)). Якщо припустити, що у нас немає базового класу під назвою Animal, то в C ++ вам доведеться зробити значну роботу, тому що компілятор не дозволить вам виконувати будь-які динамічні відправлення без загального базового класу. Індекси для vtables повинні збігатися, і цього неможливо зробити між неповторними класами. Вам потрібно мати достатньо великий vtable для зберігання віртуальних методів усіх класів у системі. Програмісти на C ++ рідко сприймають це як обмеження, оскільки вас навчили певним чином думати про дизайн класу. Я не кажу, що це краще чи гірше.
При пізньому прив'язуванні час виконання подбає про це без загального базового класу. Зазвичай існує система хеш-таблиць, яка використовується для пошуку методів у класах із системою кешування, що використовується в диспетчері. Де в C ++, компілятор знає всі типи. У мові з пізньою прив'язкою самі предмети знають свій тип (він не безтиповий, самі об'єкти точно знають, ким вони є в більшості випадків). Це означає, що я можу мати масиви різних типів об’єктів, якщо хочу (Леви, Тигри та Ведмеді). І ви можете реалізувати пересилання та прототипування повідомлень (дозволяє змінювати поведінку кожного об’єкта без зміни класу) та всілякі інші речі набагато більш гнучкими та призводять до менших витрат коду, ніж у мовах, які не підтримують пізнє прив’язування .
Ви коли-небудь програмували на Android і використовували findViewById ()? Ви майже завжди в кінцевому підсумку віддаєте результат, щоб отримати правильний тип, і кастинг в основному бреше компілятору і відмовляється від усієї статичної перевірки доброти, яка повинна зробити статичні мови вищими. Звичайно, ви могли б замість цього знайти findTextViewById (), findEditTextById () та мільйон інших, щоб ваші типи повернення збігалися, але це викидання поліморфізму у вікно; можливо ціла основа ООП. Мова з пізньою прив'язкою, ймовірно, дозволить вам просто індексувати ідентифікатор і поводитися з нею як з хеш-таблицею і не хвилювати, який тип індексується і не повертається.
Ось ще один приклад. Скажімо, у вас є клас Лев, і його поведінка за замовчуванням з’їдає вас, коли ви його бачите. У C ++, якщо ви хотіли мати одного "навченого" лева, вам потрібно скласти новий підклас. Прототипування дозволить вам просто змінити один або два методи конкретного Лева, які потрібно змінити. Це клас і тип не змінюються. C ++ не може цього зробити. Це важливо, оскільки коли у вас є новий "AfricanSpottedLion", який успадковується від Lion, ви можете його також навчити. Прототипування не змінює структуру класу, тому його можна розширити. Як правило, ці мови обробляють проблеми, які зазвичай вимагають багаторазового успадкування, або, можливо, множинне успадкування - це спосіб вирішення проблеми з відсутністю прототипування.
FYI, Objective-C - це C з доданим повідомленням про передачу SmallTalk, а SmallTalk - оригінальним ООП, і обидва пізно пов'язані з усіма описаними вище функціями. Мови з пізньою прив'язкою можуть бути трохи повільнішими з точки зору мікрорівню, але часто можуть дозволити структуру коду таким чином, щоб він був більш ефективним на макрорівні, і все зводиться до переваг.