Чи існує інше обґрунтування використання абстрактних класів / інтерфейсів у C ++ та Java


13

За словами Герба Саттера, слід віддавати перевагу абстрактним інтерфейсам (всі чисті віртуальні функції) абстрактним класам на C ++, щоб максимально відключити реалізацію. Хоча я особисто вважаю це правило дуже корисним, останнім часом я приєднався до команди з багатьма програмістами Java, і в коді Java ця інструкція, здається, не існує. Функції та їх реалізація дуже часто розташовані в абстрактних класах. Отже, я зрозумів, що Herb Sutter не так навіть для C ++, чи є загальна різниця у використанні абстрактних функцій на C ++ порівняно з Java. Чи абстрактні класи з кодом реалізації є більш чутливими на Java, ніж у C ++, і якщо так, чому?


1
У мене виникли певні сумніви, і, нарешті, я поставив це тут, тому що це могло бути через деякі принципи дизайну, яких я не маю про java oo. Тож мова йде не про загальну пораду, а більше про правильне та неправильне користування мовою
Мартін

Інтерфейси мають бути виключно віртуальними. Ідея абстрактних класів полягає в тому, що вони частково реалізовані, і справа в реалізації повинна заповнювати прогалини без повторення коду (наприклад, навіщо писати (байт) і писати (int) у кожному підкласі, коли ви можете мати абстрактний виклик запису класу (байт) від write (int))

1
Можливо, пов'язане: stackoverflow.com/q/1231985/484230 дає причину віддавати перевагу абстрактним класам на Java. Для C ++ ця причина, схоже, не відповідає дійсності через наявність вільних функцій, які можуть додати функціональність на рівні інтерфейсу
Мартін

1
Я думаю, що «Золоте правило» полягає в тому, щоб «зробити ненормативні класи абстрактними», але це не робить ніяких «лише чистих» або «порожніх» вимог.
Керрек СБ

1
Якщо він працює для вас, він працює для вас. Я дійсно не бачу, чому люди панікують, коли їх код більше не дотримується останніх думок.
Джеймс

Відповіді:


5

ООП має склад і заміну.

C ++ має багаторазове успадкування, спеціалізацію шаблонів, вбудовування та семантику значення / переміщення / покажчика.

Java має єдине успадкування та інтерфейси, вбудовувальну та довідкову семантику.

Загальний спосіб, коли школа ООП використовує ці мови, - це успадкування для заміни об'єктів та вбудовування для композиції. Але вам також потрібен спільний пращур і спосіб виконання часу (у C ++ називається dynamic_cast, у Java просто запитують інтерфейс у іншого).

Java робить це все за власною java.lang.Objectвкоріненою ієрахією. У C ++ немає заздалегідь заданого загального кореня, тому вам слід принаймні визначити його, щоб дійти до тієї ж "картинки" (але це обмежує деякі можливості C ++ ...).

Після цього, можливість поліморфізму компіляції в часі (подумайте на CRTP) та значення семантики може запропонувати також інші альтернативи способу перенесення поняття "OOP-об'єкт" у програму C ++.

Можна навіть уявити єресі використовувати вбудоване та неявне перетворення для управління заміщенням та приватним успадкуванням для управління композицією, фактично перетворюючи традиційну шкільну парадигму. (Звичайно, цей шлях на 20 років молодший за інші, тому не сподівайтесь на широку підтримку громадськості у цьому)

Або ви можете уявити собі віртуальну загальну базу для всіх класів, інтерфейс форми (без реалізації) для остаточних класів (повністю реалізований), що проходить через частково реалізовані інтерфейси і навіть кластерні інтерфейси, використовуючи "домінування" як передачу від інтерфейсу до реалізацій через "багатоскладований -паралелограма »схема успадкування.

Порівнюючи OOP з java з C ++, припускаючи, що існує лише один і єдиний спосіб OOP - обмеження можливостей обох мов.

Примушення C ++ суворо дотримуватися ідіомів кодування Java - це денатурація C ++, оскільки змушує Java поводитись як C ++ - подібна мова денатуює Java.

Це не питання "чутливості", а різних "механізмів агрегації" у двох мовах і по-різному поєднувати їх, що робить одну ідіому вигіднішою в одній мові, ніж іншу, і навпаки.


1
Я вважаю, що ця відповідь є дуже цікавою, оскільки вона коротко описує мовні особливості як інструмент oo та принципи дизайну лише як допомогу, а не вчення. Однак вам не потрібен загальний корінь, якщо ви хочете робити oo в c ++. Це просто неправильно, також для того, що у вас є оператори та шаблони (які є дуже потужною альтернативою основного дизайну дерева Java, як ви також вказали). Крім того, ваші бали найцінніші з усіх відповідей
Мартін

1
@Martin: В «технічному сенсі» ти маєш рацію, але якщо вам потрібно під час виконання polymorophism (так як фактичний тип конкретизованих об'єктів залежить від введення програми) в «корінь» ( «а» є стаття, а НЕ ярлик для " один і єдиний ") - це те, що робить усі об'єкти" двоюрідними братами ", а ієрархія може змінюватись за часом. Різні коріння походять з різних предків, не пов'язаних один з одним. Чи це "добре" чи "погано" - це питання контексту, а не ідіоми.
Еміліо Гаравалья

Це правда. Я подумав, що ви маєте на увазі штучне подання одного загального корінця на всю програму c ++ і вважав це дефектом, якого його немає, порівняно з java. Але після редагування ви робите чіткий погляд. Ще раз дякую
Мартін

12

Принцип справедливий для обох мов, але ви не робите чесного порівняння. Ви повинні порівнювати C ++ чисті абстрактні класи з інтерфейсами Java.

Навіть у C ++ ви можете мати абстрактні класи, у яких реалізовані деякі функції, але випливають із чисто абстрактного класу (без реалізації). У Java у вас будуть ті самі абстрактні класи (з деякими реалізаціями), які можуть виходити з інтерфейсів (без реалізації).


Тож коли ви віддасте перевагу абстрактному класу над класом інтерфейсу в c ++. Я завжди вибирав інтерфейс плюс функції, які не є членами, в c ++.
Мартін

1
@Martin, що залежить від дизайну. В основному завжди віддайте перевагу інтерфейсу. Але правила " завжди " мають винятки ...
Лучіан Григоре

Правда, але в Java-коді я бачу абстрактні класи, що значною мірою представляють більшість. Чи може це бути пов’язано з тим, що у Java не можливі вільні функції, що працюють на інтерфейсах?
Мартін

3
@Martin добре безкоштовні функції на Java взагалі не можливі, тому це може бути причиною, так. Гарне місце! Відповів на власне запитання! Ви можете додати відповідь самостійно, я думаю, що це все.
Лучіан Григоре

4

Як правило, ті самі принципи OO справедливі для Java та C ++. Однак одна велика різниця полягає в тому, що C ++ підтримує багатонаступне успадкування, тоді як у Java ви можете успадковувати лише один клас. Це головна причина, чому я вважаю, що у Java є інтерфейси, які я вважаю, щоб доповнити відсутність багаторазового успадкування і, ймовірно, обмежити те, що ви можете з цим зробити (оскільки є багато критики щодо зловживання багаторазовим успадкуванням). Тож, ймовірно, на увазі програмістів Java існує сильніша відмінність між абстрактними класами та інтерфейсами. Абстрактні класи використовуються для обміну та успадкування поведінки, тоді як інтерфейси просто використовуються для додання додаткової функціональності. Пам'ятайте, що в Java ви можете успадкувати лише один клас, але у вас може бути багато інтерфейсів. У C ++ , проте, чисті абстрактні класи (тобто «C ++ інтерфейс») є використовується для спільного використання та успадкування поведінки на відміну від мети Java-інтерфейсу (хоча для виконання функцій все ще потрібно), отже, використання відрізняється від інтерфейсів Java.


0

Іноді має сенс мати деяку реалізацію за замовчуванням. Наприклад, загальний метод PrintError (string msg), застосовний до всіх підкласів.

virtual PrintError(string msg) { cout << msg; }

Це все-таки може бути відмінено, якщо дійсно потрібно, але ви можете врятувати клієнта певних клопотів, дозволяючи їм просто викликати загальну версію.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.