Критика Сі + +. Віртуальні функції *, C / C + +, Програмування, статті

Ян Джойнер, Мир ПК

Мова програмування працює на багатьох рівнях і виконує різні функції, а тому повинен критично розглядатися по відношенню саме до цих рівнів і функцій. Саме віртуальні функції – основний об’єкт критики мови Cи + +.

Cи + + являє собою цікавий експеримент з адаптації можливостей об’єктної технології до традиційного мови програмування. Бьерн Страуструп цілком гідний оплесків за те, що йому в голову прийшла думка злити обидві технології воєдино. У той же час в Cи + + збереглися проблеми старого покоління засобів програмного виробництва. Мова Сі + + володіє тим перевагою перед Cи, що підтримує деякі аспекти об’єктної технології, які можуть бути використані для обмеженого проведення аналізу вимог і проектування. Проте процеси аналізу, проектування та реалізації проекту всі ще в значній мірі залишаються зовнішніми по відношенню до Cи + +. Таким чином, в Cи + + не реалізовані важливі переваги об’єктної технології, які прямо б привели до економічному виробництва програмної продукції.

Віртуальні функції

Поліморфізм – основоположна концепція об’єктно-орієнтованого програмування. У мові Сі + + ключове слово virtual надає функції можливість стати поліморфічне, якщо вона буде переписана (Перевизначена) в одному класі-нащадку або більше. Однак слово virtual аж ніяк не є необхідним, оскільки будь-яка функція, перевизначення (overriden) в класі-нащадку, може бути поліморфічне. Компілятору тільки потрібно генерувати комутуючих код для істинно поліморфічне процедур.

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

Сі + + також дозволяє функціям бути перевантаженими (overloaded); в такій ситуації виклик потрібної функції залежить від аргументів. Різниця між перевантаженими і поліморфічне (перевизначеними) функціями полягає в тому, що в перевантажених функціях потрібна визначається при компіляції, а в разі поліморфічне визначається при виконанні.

Коли батьківський клас проектується програмістом, то доводиться тільки здогадуватися, чи може бути функція перевизначена або перевантажена. Клас-нащадок здатний перевантажувати функцію в будь-який час, але це не відповідає більш важливого механізму поліморфізму, коли автор батьківського класу повинен точно задавати, що процедура буде віртуальною. Тоді компілятор встановить комутуючу запис для даної функції в таблиці перемикання класів. Значить, на програміста лягає турбота про все те, що автоматично повинно виконуватися самим компілятором і що робить компілятор в інших мовах. Такий пережиток успадкований Сі + + через те, що спочатку він був реалізований за допомогою інструментарію UNIX, а не за допомогою спеціальної підтримки компілятора і компонувальника.

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

Існують три варіанти, пов’язані з перевизначенням, які описуються словами «не повинно», «може» і «має».

  1. Перевизначення процедури заборонено. Класи-нащадки повинні використовувати процедуру в тому вигляді, як вона є

  2. Процедура може бути перевизначена. Класи-нащадки можуть застосовувати процедуру такою, як вона є, або ж забезпечити свою власну реалізацію в суворій відповідності з початковим описом інтерфейсу

  3. Процедура є абстрактною. Реалізація не надається, і кожен неабстрактний клас-нащадок має забезпечувати свою власну реалізацію. Це і є поліморфізм.

Розробник базового класу повинен прийняти варіанти 1 і 3, а класів-нащадків – 2. Для всіх варіантів мову зобов’язаний надавати відповідний синтаксис.

Варіант 1

Мова Сі + + не забороняє перевизначення процедури в класі-нащадку. Навіть приватні віртуальні процедури можуть бути перевизначені. Саккіні [1] вказує на те, що клас-нащадок може перевизначати приватну віртуальну функцію і тоді, коли до неї немає ніякого доступу.

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

У цьому прикладі клас B має розширені або взяті з класу A замінені процедури. Для об’єктів типу B повинна бути викликана процедура B :: nonvirt. Програмісту-користувачеві класу Сі + + додає гнучкість, тобто можна викликати або A :: nonvirt, або B :: nonvirt. Але того ж можна було домогтися набагато простіше і більш прямим шляхом. A :: nonvirt і B :: nonvirt слід дати різні імена. В цьому випадку програміст викликає потрібну йому процедуру явно, а не за рахунок якихось темних махінацій мови, що призводять до можливості помилок.

Тепер розробник класу B має прямий контроль над інтерфейсом цього класу. Додаток вимагає, щоб клієнти класу B могли викликати і A :: nonvirt, і B :: nonvirt. Розробник класу B забезпечує виклик явним чином, що можна вважати хорошим об’єктно-орієнтованим проектуванням, при якому надаються чітко визначені інтерфейси. Сі + + дозволяє програмістам-користувачам класу здійснювати різні трюки з інтерфейсами, зовнішніми по відношенню до даного класу, і розробник класу B не в силах запобігти виклик A :: nonvirt. Об’єкти класу B містять свої власні спеціалізовані процедури nonvirt, але розробник класу B не має достатнього контролю над інтерфейсом цього класу B, щоб гарантувати виклик коректної версії цієї процедури.

Сі + + також не захищає клас B від інших змін, що вносяться в систему. Припустимо, що нам потрібно створити такий клас C, у якого процедура nonvirt повинна бути віртуальною. Для цього nonvirt в класі A також повинна бути віртуальною, що зводить нанівець трюк з B :: nonvirt. Вимога класу C мати віртуальну процедуру змушує вносити зміни в базовий клас, що зачіпають всіх інших нащадків даного базового класу. Це робиться замість локалізації нового специфічного вимоги в новому класі. Подібні дії йдуть врозріз з ідеєю об’єктно-орієнтованого програмування мати слабосвязанних класи, для того щоб нові вимоги і зміни мали локальним характером і не змушували вносити корективи всюди. Потенційно це може привести до конфлікту з іншими існуючими частинами системи.

Ще один аргумент полягає в тому, що будь-який оператор повинен постійно мати одну і ту ж семантику. Поліморфічне інтерпретація оператора виду a-> f () полягає в тому, що для об’єкта, на який посилається a, викликається найбільш підходяща реалізація f (), незалежно від того, чи належить цей об’єкт типу A або ж нащадку класу A. Проте в мові Сі + + для того щоб чітко уявляти собі, що ж викликає a-> f (), програміст повинен знати, чи визначена функція f () як віртуальна або як Невіртуальна. Отже, про оператор a-> f () не можна сказати, що він не залежить від реалізації, і принцип приховування деталей реалізації порушується. Зміна в описі f () буде впливати на семантику виклику. А от незалежність від реалізації означає, що її зміни не зачіпають семантику виконуваних операторів.

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

Щоб познайомитися ще з одним прикладом порушення цілісності семантики оператора a-> f (), подивіться розділ 10.9c в керівництві [2, с. 232].

Ні в Eiffel, ні в Java подібних проблем не виникає. Їх механізми простіше і зрозуміліше, вони не призводять до сюрпризів, яких вистачає у Сі + +. У мові Java все є віртуальним, і це призводить до того, що метод повинен бути не перевизначений або визначений з кваліфікаторів final. Мова Eiffel дозволяє специфікувати процедуру як заморожену, і тоді вона не може бути перевизначена в класах-нащадках.

Варіант 2

Цей варіант перевизначення відкритий для розробників класів-нащадків, однак у мові Сі + + рішення має прийматися в базовому класі. Якщо говорити про об’єктно-орієнтованому проектуванні, то рішення від чого-небудь відмовитися настільки ж важливі, як і на щось погодитися. Остаточні ж рішення потрібно відтягувати до самого останнього моменту. Така стратегія запобігає від появи помилок на самих ранніх стадіях програмування. При прийнятті поспішних рішень ви часто будете потрапляти в глухий кут, спираючись на те, що згодом виявиться некоректним. Сі + + вимагає, щоб батьківський клас специфікований потенційний поліморфізм через віртуальні методи (хоча проміжний клас в ланцюжку спадкування теж здатний вводити віртуалізацію). З цього випливає, що процедура може бути перевизначена в класах-нащадках. Такий підхід вельми проблематичний, оскільки процедури, які фактично не є поліморфічне, доступні не через прямий процедурний виклик, а через декілька менш ефективну схему віртуальних таблиць. (Це не такі вже й значні накладні витрати, проте об’єктно-орієнтовані програми мають тенденцію використовувати велику кількість маленьких процедур, що в сумі веде до підвищення накладних витрат.) Політика мови Сі + + складається в тому, що процедури, які можуть бути перевизначені, повинні бути оголошені як віртуальні.

Ось яка критика на адресу віртуальних функцій звучить з вуст Румба і його колег [3]: «Сі + + володіє механізмами спадковості й динамічного дозволу методів (run-time method resolution), а в той же час структура даних Сі + + не є за своєю природою об’єктно-орієнтованої. Дозвіл методу і здатність перевизначати операцію в підкласі доступні тільки в тому випадку, коли операція оголошена як віртуальна в суперкласу. Таким чином, слід передбачити необхідність перевантажувати метод і заносити цю можливість у вихідне опис класу. На жаль, розробник класу може не врахувати потреби задавати спеціалізовані підкласи і не знати, що ті чи інші операції будуть в підкласі перевизначені. Значить, суперклас часто повинен зазнавати змін, коли задається підклас. Звідси випливає істотне обмеження на багаторазове використання бібліотечних класів при створенні підкласів, особливо коли недоступна бібліотека у вихідних текстах. (Безумовно, можна оголошувати всі операції як віртуальні, але тоді значно зростуть накладні витрати на використання пам’яті і виклик функцій.) »

Проте віртуалізація – невдалий механізм для має з ним справу програміста. Інша проблема в Сі + + пов’язана з помилковим перевизначенням методів.

Компілятор може виявляти поліморфізм і генерувати відповідний код віртуалізації там і тільки там, де це потрібно. Необхідність визначати віртуальні функції – зайва турбота для програміста. В основному саме з цієї причини Сі + + і є збитковим об’єктно-орієнтованою мовою. Програміст повинен постійно дбати про низькорівневих деталях, які могли б автоматично оброблятися компілятором.

Процедура базового класу може бути перевизначена без всякого умислу. Компілятор повинен повідомляти про помилковий перевизначенні імені в рамках одного і того ж простору імен, якщо тільки розробник класу-нащадка явно не вкаже, що він робить це навмисно. Може бути використано і те ж саме ім’я, але тоді програміст повинен йти на це свідомо і задавати його явно, особливо в тих середовищах, де системи збираються з уже існуючих компонентів. До тих пір поки програміст явно не перевантажить вихідне ім’я, буде генеруватися помилка про те, що має місце дублювання імен. У той же час Сі + + успадкував початковий підхід мови Симула. В інших мовах він був удосконалений, і вони пішли за більш вдалому і більш чітко вираженого шляху, щоб уникнути ненавмисних помилок перевизначення.

Рішення полягає в тому, що virtual не повинен задаватися в батьківському класі. Коли потрібно динамічне поліморфічне зв’язування на етапі виконання, то клас-нащадок має специфікувати перевизначення функції, а коли необхідно статичне поліморфічне зв’язування на етапі компіляції, то він буде задавати перевантаження функції. Подібна схема має значні переваги: ​​у разі поліморфічне функцій компілятор може перевіряти відповідність заголовків функцій, а в разі перевантажених – їх деякі відмінності.

У мові Java немає ключового слова virtual, а всі методи – потенційно поліморфічне. Java використовує прямий виклик замість пошуку в таблиці динамічних методів, де метод може бути статичним, приватним або фінальним. Значить, будуть неполіморфіческіе функції, які повинні викликатися динамічно, а через динамічної природи Java подальша оптимізація неможлива.

Мови Eiffel і Object Pascal вирішують цю проблему таким чином, що розробнику класу-нащадка потрібно задавати перевизначення усвідомлено. Додаткова вигода від подібного рішення полягає в тому, що згодом люди, які вивчають або супроводжують даний клас, можуть легко виявити перевизначені процедури і що дане конкретне опис відноситься саме до класу-нащадка, а не до батьківських класах. Таким чином, варіант 2 реалізується там, де йому і місце, тобто в класах-нащадках. І Eiffel, і Object Pascal оптимізують виклики: вони тільки генерують для динамічного зв’язування комутуючі записи в таблиці методів, коли процедура істинно поліморфічне.

Варіант 3

У варіанті 3 використовується чиста віртуальна функція. Процедура тут є невизначеною, а клас абстрактним і не допускає безпосереднього породження. Тому клас-нащадок має доопределить цю процедуру. Всі нащадки, які не роблять цього, також відносяться до абстрактних класів. Така концепція коректна, але все-таки слід подивитися віртуальні функції, де піддається критиці їх синтаксис. Java також має абстрактні методи, а в мові Eiffel реалізація позначається як deferred (відкладена).

Чисті віртуальні функції

Чисті віртуальні функції (pure virtual functions) надають механізм для збереження функції у вигляді невизначеною і абстрактною. Клас, що містить таку абстрактну функцію, не може бути породжений безпосередньо, а неабстрактний клас-нащадок має визначити її. Синтаксис чистої віртуальної функції в Сі + + виглядає так: virtual void fn () = 0.

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

Запис = 0 була б корисна лише для розробника компілятора, так як при реалізації в таблицю віртуальних викликів заноситься 0. Таким чином, зайвий раз демонстріруeтся, як деталі реалізації, не мають ставлення до програмісту, у мові Сі + + видно зовні.

З точки зору математики 0 аж ніяк не означає відсутність. Зазвичай 0 – це просто інше число. Використання нуля в значенні «відсутній» призводить до смисловому розриву. У світі баз даних застосовується значення «не відомо». Якщо 0 використовується в цьому значенні, то виникає проблема, коли значення відомо і дорівнює 0. Запис виду = 0 викликає накопичення помилок. Перевантажуються не тільки такі ключові слова, як virtual і static, але і 0 починає означати те, що математично не має сенсу. Java і Eiffel використовують набагато більш зрозумілий синтаксис. В Java це виглядає як abstract void fn (), а в Eiffel процедуру потрібно задавати як відкладену (deferred). Отже, деталі реалізації відкладаються до рішення в класі-нащадку: r is deferred end. Ви можете специфікувати та інші абстрактні властивості у вигляді перед-і пост-умов. У Eiffel використовується більш вдала термінологія, так, під deferred розуміється, що реалізація відкладається. Процедура, що має реалізацію, все ще володіє абстрактної формою, причому під терміном «абстрактний» зовсім не слід розуміти «нереалізований».

«Віртуальний» – це поняття, складне для сприйняття. Більш прості для розуміння відповідні концепції поліморфізму і динамічного зв’язування, перевизначення і перевантаження, оскільки вони орієнтовані на предметну область. Віртуальні процедури представляють по суті механізм реалізації поліморфізму. Поліморфізм – «що», а віртуальний – це «як». Мови Smalltalk, Objective C, Java і Eiffel використовують зовсім інший механізм для реалізації поліморфізму. Віртуальні процедури – приклад того, як мова Сі + + порушує концепції об’єктно-орієнтованого програмування. Програміста змушують працювати на основі низькорівневих концепцій, а не користуватися високорівневими об’єктно-орієнтованими. Подібні механізми можуть бути цікаві для теоретиків і розробників компіляторів, тоді як практикам немає жодної потреби в них вникати, а потрібно застосовувати лише як високорівневих концепцій. Неминучість використання цих механізмів на практиці призводить до дуже кропіткої і чреватої помилками роботі, що може загальмувати адаптацію програмного забезпечення до нових досягнень у відповідних технологіях і механізмах її підтримки.

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

Рішення Сі + + полягає в тому, що він слідує філософії мови Cи уникати ключових слів, причому це часто йде на шкоду розумінню. Ключове слово буде реалізовувати таку концепцію набагато ясніше, наприклад pure virtual void fn () або abstract void fn (). Математична нотація, що застосовується в Сі + +, припускає, що можуть використовуватися величини, відмінні від 0. Так, якщо функції буде присвоєно значення 13: virtual void fn () = 13, то функція або реалізована, або не визначена. Будь аналітик все зрозумів би, якби це було булево значення, яке виражалося б одним ключовим словом. Усунути таку неясність можна, якщо визначити = 0 як abstract:

#define abstract = 0
virtual void fn() abstract;

Термін «чиста віртуальна» – некоректне мовне вираження. Це поєднання слів, що несуть в собі протилежні значення. «Чистий» означає щось реальне, щось без домішок. Наприклад, «чисте золото». «Віртуальний» – щось таке, чого немає в природі. Наприклад, «віртуальна пам’ять». Правда, «віртуальне золото» може бути фальшивим. Як уже раніше зазначалося, «віртуальний» – для розуміння концепція складна. І коли вона зустрічається в поєднанні зі словом «чистий», стає зовсім не по собі.

Бьерн Страуструп дає таке пояснення дивним увазі записи = 0: «Курйозний синтаксис = 0 був обраний як очевидна альтернатива введенню ключових слів pure або abstract, оскільки в той час я не бачив можливості вводити ще одне ключове слово. Я припускав, що в Release 2.0 абстрактні класи не увійдуть. Щоб не ризикувати з затримкою в прийнятті рішення і не вступати в тривалі дискусії, я використав традиційне угоду Сі та Сі + + про те, що 0 носить значення «відсутній» ».

Висновок

Спадкування передбачає тісні взаємини. Воно пропонує фундаментальний шлях для складання програмних компонентів. Об’єкти, які є екземплярами деякого класу, також будуть і екземплярами всіх батьків даного класу. Для ефективного об’єктно-орієнтованого проектування цілісність цих відносин повинна чітко дотримуватися. Кожне перевизначення в підкласі має бути перевірено на цілісність з вихідним описом в батьківському класі. І підклас повинен дотримуватися вимог, встановлених в батьківському класі. Вимоги, які не можуть бути виконані, сигналізують про помилку проектування або про те, що спадкування в даному випадку не підходить. Цілісність в сенсі наслідування – це фундаментальний принцип об’єктно-орієнтованого проектування. Реалізація в мові Сі + + невіртуальної перевантаження (non-virtual overloading) і перевантаження по заголовку функцій (overloading by signature) означає, що компілятор не може перевіряти цю цілісність. Сі + + не підтримує даний аспект об’єктно-орієнтованого проектування. Це призводить до великої і вельми дорогого розриву між аналізом вимог, проектуванням і реалізацією.

Спадкування може бути розцінена як синтаксичне або як семантичне. Сейко і його колеги в роботі [5] формулюють це таким чином: «Синтаксичне спадкування позначає спадкування структури або опису методів і тому відноситься до багаторазового використання програмного коду (і до перевантаження коду для успадкованих методів). Семантичне спадкування позначає спадкування семантики об’єкта, тобто самих об’єктів. Цей вид спадкування відомий з семантичних моделей даних, де він використовується для моделювання такого об’єкта, який виступає в додатку відразу в декількох іпостасях ». Сейко з колегами зосередили свою увагу саме на семантичній формі наслідування. Поведінкове або семантичне спадкування висловлює роль об’єкта усередині даної системи.

Вегнер [6], однак, переконаний, що спадкування коду повинне становити велику практичну цінність. Він співвідніс відмінність між синтаксичним і семантичним спадкуванням з ієрархіями коду та поведінки і зробив висновок про те, що вони рідко сумісні один з одним і часто входять у суперечність. Вегнер також задається питанням: «Яким чином повинна бути обмежена модифікація успадкованих атрибутів?» Спадкування коду забезпечує основу для модульності. Поведінкове ж спадкування підтримує моделювання через ставлення «є» (is-a). І те й інше грає корисну роль. Обидва потребують перевірки цілісності, при якій комбінації в плані наслідування мають певний реальний зміст.

Видається, що спадкування – найбільш потужний механізм у вкрай обмеженій формі семантики, що зберігає відносини спадкування. Підклас не повинен порушувати умов, встановлених його батьківським класом.

Програмні компоненти подібні шматочках збирається картинки. Коли вирішується подібна головоломка, то необхідно, зрозуміло, дотримати форму шматочків, але набагато важливіше, щоб зібрана картинка не вийшла безглуздою. Збірка програмних компонентів – завдання куди складніше, адже збирається картинка до перемішування її шматочків була закінченою. А збірка програмних компонентів – це зведення системи, якою ніколи не існувало.

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

Література

1. Sakkinen M. Inheritance and Other Main Principles of C++ and Other Object-Oriented Languages // Structured Programming. 1992. V.13.

2. Ellis, Stroustrup B. The annotated C++ Reference Manual. AT&T, 1990.

3. Rumbaugh, Blaha, Premerlani, Eddy, Lorensen. Object-Oriented Modeling and Design. Prentice-Hall, 1991.

4. Stroustrup В. Design and Evolution of C + +. Addison Weslеy, 1994.

5. Saake, Jungclaus, Ehrich. Object-Oriented Specification and Stepwise Refinement // IFIP Workshop on Open Distributed Processing. Berlin, 1991.

6. Wegner P. Concepts and Paradigms of Object-Oriented Programming // ACM SIGPLAN OOPS Messenger. 1990. V.1, № 1.

* Тут публікується фрагмент великої роботи Яна Джойнер, згодом покладеної в основу його книги «Objects Unencapsulated: Eiffel, Java, and C + +» (Prentice-Hall, 1999). У російський варіант увійшли фрагменти, узяті з 2-ї і 3-ї редакції роботи Яна Джойнер «С + +? А Critique of C + + ».

Від автора (до російського видання в «Світі ПК»)

Мені дуже приємно, що ви вирішили опублікувати в своєму журналі фрагмент моєї роботи «C + +? A Critique of C + + »(1996), оскільки Сі + + – мова, що вимагає досить інтенсивної критики. Він являє собою не занадто вдалу реалізацію об’єктно-орієнтованої технології, і тому його недоліки просто необхідно піддавати критичному аналізу.

Безперечно, один з небагатьох, хто позначив чітку межу для об’єктно-орієнтованої технології, – Бертран Мейер (Bertrand Meyer), автор мови Eiffel. Він написав кілька книг, присвячених об’єктної технології, і з ними ви обов’язково повинні познайомитися. У своїй критиці Сі + + йому вдається обходитися без кулачного бою. Серед тих його книг, які можна порекомендувати вашим читачам, слід зазначити дві, випущені видавництвом Prentice-Hall: «Object-oriented Software Construction» і «Object Success: A Managers guide to object orientation, its impact on the corporation and its use for reengineering the software process».

Я переконаний в тому, що об’єктно-орієнтована технологія може багато чого запропонувати для вирішення проблем, що стоять перед сучасними складними програмними системами. Але одночасно Сі + + приносить всім колосальне розчарування – він увібрав в себе всі погані і старі кошти, а також привніс в об’єктну технологію абсолютно непотрібну складність. Навіщо потрібна мова, наскрізь просочений низькорівневими конструкціями? Найбільш вірний шлях до успіху – використання чистого об’єктно-орієнтованої мови, що володіє інтерфейсом з мовою програмування С або з іншими низькорівневими мовами. Це забезпечить хороші підтримку і супровід, переносимість і якість.

Мені хочеться, щоб ви досягли успіху у створенні ефективного та якісного програмного забезпечення, і я вважаю, що ви знайдете частина відповідей на які стоять перед вами питання саме в об’єктної орієнтації, а не в мові Сі + +. Не треба думати, що критики Сі + + – релігійні фанатики або диваки, якими їх намагаються представити його прихильники. Ми розкриваємо недоліки Сі + + і радимо звернути увагу на набагато досконаліші підходи, якими можна скористатися вже зараз.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*