Из истории создания C++

.

Язык C++ — единственный (из самых значительных) язык программирования, который может освоить любой программист. Это может показаться очень серьезным заявлением, но оно — не преувеличение. C++ — это центр притяжения, вокруг которого «вращается» всё современное программирование. Его синтаксис и принципы разработки определяют суть объектно-ориентированного программирования. Более того, C++ проложил «лыжню» для разработки языков будущего. Например, как Java, так и C# — прямые потомки языка C++. C++ также можно назвать универсальным языком программирования, поскольку он позволяет программистам обмениваться идеями.

Сегодня быть профессиональным программистом высокого класса означает быть компетентным в C++. C++ — это ключ к современному программированию.
Приступая к изучению C++, важно знать, как он вписывается в исторический контекст языков программирования. Понимая, что привело к его созданию, какие принципы разработки он представляет и что он унаследовал от своих предшественников, вам будет легче оценить суть новаторства и уникальность средств C++. Именно поэтому в данной главе вам предлагается сделать краткий экскурс в историю создания языка программирования C++, заглянуть в его истоки, проанализировать его взаимоотношения с непосредственным предшественником ©, рассмотреть его возможности (области применения) и принципы программирования, которые он поддерживает. Здесь также вы узнаете, какое место занимает C++ среди других языков программирования.
Истоки C++
История создания C++ начинается с языка С. И немудрено: C++ построен на фундаменте С. C++ и в самом деле представляет собой супермножество языка С. (Все компиляторы C++ можно использовать для компиляции С-программ.) C++ можно назвать расширенной и улучшенной версией языка С, в которой реализованы принципы объектно-ориентированного программирования. C++ также включает ряд других усовершенствований языка С, например расширенный набор библиотечных функций. При этом «вкус и запах» C++ унаследовал непосредственно из языка С. Чтобы до конца понять и оценить достоинства C++, необходимо понять все «как» и «почему» в отношении языка С.
Создание языка С
Появление языка С потрясло компьютерный мир. Его влияние нельзя было переоценить, поскольку он коренным образом изменил подход к программированию и его восприятие. Язык С стал считаться первым современным «языком программиста», поскольку до его изобретения компьютерные языки в основном разрабатывались либо как учебные упражнения, либо как результат деятельности бюрократических структур. С языком С все обстояло иначе. Он был задуман и разработан реальными, практикующими программистами и отражал их подход к программированию. Его средства были многократно обдуманы, отточены и протестированы людьми, которые действительно работали с этим языком. В результате этого процесса появился язык, который понравился многим программистам-практикам.
Язык С быстро завоевал умы и сердца многочисленных приверженцев, у которых возникло к новому языку почти религиозное чувство, что способствовало быстрому и широкому его распространению в сообществе программистов. Короче говоря, С — это язык, который разработан программистами для программистов. Именно это и обусловило его бешеный успех.
Язык С изобрел Дэнис Ритчи (Dennis Ritchie) для компьютера PDP-11 (разработка компании DEC — Digital Equipment Corporation), который работал под управлением операционной системы (ОС) UNIX. Язык С — это результат процесса разработки, который сначала был связан с другим языком — BCPL, созданным Мартином Ричардсом (Martin Richards). Язык BCPL индуцировал появление языка, получившего название В (его автор — Кен Томпсон (Ken Thompson)), который в свою очередь привел к разработке языка С. Это случилось в начале 70-х годов.
На протяжении многих лет стандартом для языка С де-факто служил язык, поддерживаемый ОС UNIX и описанный в книге Брайана Кернигана (Brian Kernighan) и Дэниса Ритчи The С Programming Language (Prentice-Hall, 1978). Однако формальное отсутствие стандарта стало причиной расхождений между различными реализациями языка С. Чтобы изменить ситуацию, в начале лета 1983 г. был учрежден комитет по созданию ANSI-стандарта, призванного — раз и навсегда — определить язык С. Конечная версия этого стандарта была принята в декабре 1989, а его первая копия стала доступной для желающих в начале 1900. Эта версия языка С получила название С89, и именно она явилась фундаментом, на котором был построен язык C++.
На заметку: Стандарт С был обновлен в 1999 году, и эта версия языка С получила название С99. Новый стандарт содержит ряд новых средств, причем некоторые из них позаимствованы из C++, тем не менее они полностью совместимы с оригинальным стандартом С89. Насколько мне известно, на данный момент ни один из широко доступных компиляторов не поддерживает версию С99, и по-прежнему версия С89 определяет то, что обычно подразумевается под языком С. Более того, именно стандарт С89 послужил основой для создания языка C++. Вполне возможно, что будущий стандарт языка C++ будет включать средства, добавленные версией С99, но пока они не являются частью C++.

Язык С часто называют компьютерным языком «среднего уровня». Применительно к С это определение не имеет негативного оттенка, поскольку оно отнюдь не означает, что язык С менее мощный и развитый (по сравнению с языками «высокого уровня») или его сложно использовать (подобно ассемблеру). (Для языка ассемблера характерно символическое представление реального машинного кода, который может выполнять компьютер.) С называют языком среднего уровня, поскольку он сочетает элементы языков высокого уровня (например Pascal, Modula-2 или Visual Basic) с функциональностью ассемблера.
С точки зрения теории в язык высокого уровня заложено стремление дать программисту все, что он может захотеть, в виде встроенных средств. Язык низкого уровня не обеспечивает программиста ничем, кроме доступа к реальным машинным командам. Язык среднего уровня предоставляет программистам некоторый (небольшой) набор инструментов, позволяя им самим разрабатывать конструкции более высокого уровня. Другими словами, язык среднего уровня предлагает программисту встроенную мощь в сочетании с гибкостью.
Будучи языком среднего уровня, С позволяет манипулировать битами, байтами и адресами, т.е. базовыми элементами, с которыми работает компьютер. Таким образом, в С не предусмотрена попытка отделить аппаратные средства компьютера от программных. Например, размер целочисленного значения в С напрямую связан с размером слова центрального процессора (ЦП). В большинстве языков высокого уровня существуют встроенные инструкции, предназначенные для чтения и записи дисковых файлов. В языке С все эти процедуры выполняются посредством вызова библиотечных функций, а не с помощью ключевых слов, определенных в самом языке. Такой подход повышает гибкость языка С.
Язык С позволяет программисту (правильнее сказать, стимулирует его) определять подпрограммы для выполнения операций высокого уровня. Эти подпрограммы называются функциями. Функции имеют очень большое значение для языка С. Их можно назвать строительными блоками С. Программист может без особых усилий создать библиотеку функций, предназначенную для выполнения различных задач, которые используются его программой. В этом смысле программист может персонализировать С в соответствии со своими потребностями.
Необходимо упомянуть еще об одном аспекте языка С, который очень важен для C++: С — структурированный язык. Самой характерной особенностью структурированного языка является использование блоков. Блок — это набор инструкций, которые логически связаны между собой. Например, представьте себе инструкцию IF, которая при успешной проверке своего выражения должна выполнить пять отдельных инструкций. А если эти инструкции (специальным образом) сгруппировать и обращаться к ним как к единому целому, то такая группа образует блок.
Структурированный язык поддерживает концепцию подпрограмм и локальных переменных. Локальная переменная — это обычная переменная, которая известна только подпрограмме, в которой она определена. Структурированный язык также поддерживает ряд таких циклических конструкций, как while, do-while и for. Однако использование инструкции goto либо запрещается, либо не рекомендуется, и не несет в себе той смысловой нагрузки для передачи управления, какая присуща ей в таких языках программирования, как BASIC или FORTRAN. Структурированный язык позволяет структурировать текст программы, т.е. делать отступы при написании инструкций, и не требует строгой привязки к полям, как это реализовано в ранних версиях языка FORTRAN.
Наконец (и это, возможно, самое важное), язык С не несет ответственности за действия программиста. Основной принцип С состоит в том, чтобы позволить программисту делать все, что он хочет, но за последствия, т.е. за все, что делает программа (пусть даже очень необычное, что-то из ряда вон или даже подозрительное), отвечает не язык, а программист. Язык С предоставляет программисту практически полную власть над компьютером, но эта власть ложится на его плечи тяжким бременем ответственности.
Предпосылки возникновения языка C++
Приведенная выше характеристика языка С может вызвать справедливое недоумение: зачем же тогда, мол, был изобретен язык C++? Если С — такой хороший и полезный язык, то почему возникла необходимость в чем-то еще? Оказывается, все дело в сложности. На протяжении всей истории программирования усложнение программ заставляло программистов искать пути, которые бы позволили справиться со сложностью. C++ можно считать одним из способов ее преодоления. Попробуем лучше раскрыть эту взаимосвязь.
Отношение к программированию резко изменилось с момента изобретения компьютера. Основная причина — стремление «укротить» всевозрастающую сложность программ. Например, программирование для первых вычислительных машин заключалось в переключении тумблеров на их передней панели таким образом, чтобы их положение соответствовало двоичным кодам машинных команд. Пока длины программ не превышали нескольких сотен команд, такой метод еще имел право на существование. Но по мере их дальнейшего роста был изобретен язык ассемблер, чтобы программисты могли использовать символическое представление машинных команд. Поскольку программы продолжали расти в размерах, желание справиться с более высоким уровнем сложности вызвало появление языков высокого уровня, разработка которых дала программистам больше инструментов (новых и разных).
Первым широко распространенным языком программирования был, конечно же, FORTRAN. Несмотря на то что это был очень значительный шаг на пути прогресса в области программирования, FORTRAN все же трудно назвать языком, который способствовал написанию ясных и простых для понимания программ. Шестидесятые годы двадцатого столетия считаются периодом появления структурированного программирования. Именно такой метод программирования и был реализован в языке С. С помощью структурированных языков программирования можно было писать программы средней сложности, причем без особых героических усилий со стороны программиста. Но если программный проект достигал определенного размера, то даже с использованием упомянутых структурированных методов его сложность резко возрастала и оказывалась непреодолимой для возможностей программиста. Когда (к концу 70-х) к «критической» точке подошло довольно много проектов, стали рождаться новые технологии программирования. Одна из них получила название объектно-ориентированного программирования (ООП). Вооружившись методами ООП, программист мог справляться с программами гораздо большего размера, чем прежде. Но язык С не поддерживал методов ООП. Стремление получить объектно-ориентированную версию языка С в конце концов и привело к созданию C++.
Несмотря на то что язык С был одним из самых любимых и распространенных профессиональных языков программирования, настало время, когда его возможности по написанию сложных программ достигли своего предела. Желание преодолеть этот барьер и помочь программисту легко справляться с еще более сложными программами — вот что стало основной причиной создания C++.
Рождение C++
Итак, C++ появился как ответ на необходимость преодолеть еще большую сложность программ. Он был создан Бьерном Страуструпом (Bjarne Stroustrup) в 1979 году в компании Bell Laboratories (г. Муррей-Хилл, шт. Нью-Джерси). Сначала новый язык получил имя «С с классами» (С with Classes), но в 1983 году он стал называться C++.
C++ полностью включает язык С. Как упоминалось выше, С — это фундамент, на котором был построен C++. Язык C++ содержит все средства и атрибуты С и обладает всеми его достоинствами. Для него также остается в силе принцип С, согласно которому программист, а не язык, несет ответственность за результаты работы своей программы. Именно этот момент позволяет понять, что изобретение C++ не было попыткой создать новый язык программирования. Это было скорее усовершенствование уже существующего (и при этом весьма успешного) языка.
Большинство новшеств, которыми Страуструп обогатил язык С, было предназначено для поддержки объектно-ориентированного программирования. По сути, C++ стал объектно-ориентированной версией языка С. Взяв язык С за основу, Страуструп подготовил плавный переход к ООП. Теперь, вместо того, чтобы изучать совершенно новый язык, С-программисту достаточно было освоить только ряд новых средств, и он мог пожинать плоды использования объектно-ориентированной технологии программирования.
Однако в основу C++ лег не только язык С. Страуструп утверждает, что некоторые объектно-ориентированные средства были инспирированы другим объектно-ориентированным языком, а именно Simula67. Таким образом, C++ представляет собой симбиоз двух мощных методологий программирования.
Создавая C++, Страуструп понимал, насколько важно, сохранить изначальную суть языка С, т.е. его эффективность, гибкость и принципы разработки, внести в него поддержку объектно-ориентированного программирования. К счастью, эта цель была достигнута. C++ по-прежнему предоставляет программисту свободу действий и власть над компьютером (которые были присущи языку С), расширяя при этом его (программиста) возможности за счет использования объектов.
Несмотря на то что C++ изначально был нацелен на поддержку очень больших программ, этим, конечно же, его использование не ограничивалось. И в самом деле, объектно-ориентированные средства C++ можно эффективно применять практически к любой задаче программирования. Неудивительно, что C++ используется для создания компиляторов, редакторов, компьютерных игр и программ сетевого обслуживания. Поскольку C++ обладает эффективностью языка С, то программное обеспечение многих высокоэффективных систем построено с использованием C++. Кроме того, C++ — это язык, который чаще всего выбирается для Windows-программирования.
Важно также помнить следующее. Поскольку C++ является супермножеством языка С, то, научившись программировать на C++, вы сможете также программировать и на С! Таким образом, приложив усилия к изучению только одного языка программирования, вы в действительности изучите сразу два.
Эволюция C++
С момента изобретения C++ претерпел три крупных переработки, причем каждый раз язык как дополнялся новыми средствами, так и в чем-то изменялся. Первой ревизии он был подвергнут в 1985 году, а второй — в 1990. Третья ревизия имела место в процессе стандартизации, который активизировался в начале 1990-х. Специально для этого был сформирован объединенный ANSI/ISO-комитет (я был его членом), который 25 января 1994 года принял первый проект предложенного на рассмотрение стандарта. В этот проект были включены все средства, впервые определенные Страуструпом, и добавлены новые. Но в целом он отражал состояние C++ на тот момент времени.
Вскоре после завершения работы над первым проектом стандарта C++ произошло событие, которое заставило значительно расширить существующий стандарт. Речь идет о создании Александром Степановым стандартной библиотеки шаблонов (Standard Template Library — STL). Как вы узнаете позже, STL — это набор обобщенных функций, которые можно использовать для обработки данных. Он довольно большой по размеру. Комитет ANSI/ISO проголосовал за включение STL в спецификацию C++. Добавление STL расширило сферу рассмотрения средств C++ далеко за пределы исходного определения языка.
Однако включение STL, помимо прочего, замедлило процесс стандартизации C++, причем довольно существенно. Помимо STL, в сам язык было добавлено несколько новых средств и внесено множество мелких изменений. Поэтому версия C++ после рассмотрения комитетом по стандартизации стала намного больше и сложнее по сравнению с исходным вариантом Страуструпа. Конечный результат работы комитета датируется 14 ноября 1997 года, а реально ANSI/ISO-стандарт языка C++ увидел свет в 1998 году. Именно эта спецификация C++ обычно называется Standard C++. И именно она описана в этой книге. Эта версия C++ поддерживается всеми основными С++-компиляторами, включая Visual C++ (Microsoft) и C++ Builder (Borland). Поэтому код программ, приведенных в этой книге, полностью применим ко всем современным С++-средам.
Что такое объектно-ориентированное программирование
Поскольку именно принципы объектно-ориентированного программирования были основополагающими для разработки C++, важно точно определить, что они собой представляют. Объектно-ориентированное программирование объединило лучшие идеи структурированного с рядом мощных концепций, которые способствуют более эффективной организации программ. Объектно-ориентированный подход к программированию позволяет разложить задачу на составные части таким образом, что каждая составная часть будет представлять собой самостоятельный объект, который содержит собственные инструкции и данные. При таком подходе существенно понижается общий уровень сложности программ, что позволяет программисту справляться с более сложными программами, чем раньше (т.е. написанными при использовании структурированного программирования).
Все языки объектно-ориентированного программирования характеризуются тремя общими признаками: инкапсуляцией, полиморфизмом и наследованием. Рассмотрим кратко каждый из них (подробно они будут описаны ниже в этой книге).
Инкапсуляция
Ни для кого не секрет, что все программы, как правило, состоят из двух основных элементов: инструкций (кода) и данных. Код — это часть программы, которая выполняет действия, а данные представляют собой информацию, на которую направлены эти действия. Инкапсуляция — это такой механизм программирования, который связывает воедино код и данные, которые он обрабатывает, чтобы обезопасить их как от внешнего вмешательства, так и от неправильного использования.
В объектно-ориентированном языке код и данные могут быть связаны способом, при котором создается самостоятельный черный ящик. В этом «ящике» содержатся все необходимые (для обеспечения самостоятельности) данные и код. При таком связывании кода и данных создается объект, т.е. объект — это конструкция, которая поддерживает инкапсуляцию.
Внутри объекта, код, данные или обе эти составляющие могут быть закрытыми в «рамках» этого объекта или открытыми. Закрытый код (или данные) известен и доступен только другим частям того же объекта. Другими словами, к закрытому коду или данным не может получить доступ та часть программы, которая существует вне этого объекта. Открытый код (или данные) доступен любым другим частям программы, даже если они определены в других объектах. Обычно открытые части объекта используются для предоставления управляемого интерфейса с закрытыми элементами объекта.
Полиморфизм
Полиморфизм (от греческого слова polymorphism, означающего «много форм») — это свойство, позволяющее использовать один интерфейс для целого класса действий. Конкретное действие определяется характерными признаками ситуации. В качестве простого примера полиморфизма можно привести руль автомобиля. Для руля (т.е. интерфейса) безразлично, какой тип рулевого механизма используется в автомобиле. Другим словами, руль работает одинаково, независимо от того, оснащен ли автомобиль рулевым управлением прямого действия (без усилителя), рулевым управлением с усилителем или механизмом реечной передачи. Если вы знаете, как обращаться с рулем, вы сможете вести автомобиль любого типа. Тот же принцип можно применить к программированию. Рассмотрим, например, стек, или список, добавление и удаление элементов к которому осуществляется по принципу «последним прибыл — первым обслужен». У вас может быть программа, в которой используются три различных типа стека. Один стек предназначен для целочисленных значений, второй — для значений с плавающей точкой и третий — для символов. Алгоритм реализации всех стеков — один и тот же, несмотря на то, что в них хранятся данные различных типов. В необъектно-ориентированном языке программисту пришлось бы создать три различных набора подпрограмм обслуживания стека, причем подпрограммы должны были бы иметь различные имена, а каждый набор — собственный интерфейс. Но благодаря полиморфизму в C++ можно создать один общий набор подпрограмм (один интерфейс), который подходит для всех трех конкретных ситуаций. Таким образом, зная, как использовать один стек, вы можете использовать все остальные.
В более общем виде концепция полиморфизма выражается фразой «один интерфейс — много методов». Это означает, что для группы связанных действий можно использовать один обобщенный интерфейс. Полиморфизм позволяет понизить уровень сложности за счет возможности применения одного и того же интерфейса для задания целого класса действий. Выбор же конкретного действия (т.е. функции) применительно к той или иной ситуации ложится «на плечи» компилятора. Вам, как программисту, не нужно делать этот выбор вручную. Ваша задача — использовать общий интерфейс.
Первые языки объектно-ориентированного программирования были реализованы в виде интерпретаторов, поэтому полиморфизм поддерживался во время выполнения программ. Однако C++ — это транслируемый язык (в отличие от интерпретируемого). Следовательно, в C++ полиморфизм поддерживается на уровне как компиляции программы, так и ее выполнения.
Наследование
Наследование — это процесс, благодаря которому один объект может приобретать свойства другого. Благодаря наследованию поддерживается концепция иерархической классификации. В виде управляемой иерархической (нисходящей) классификации организуется большинство областей знаний. Например, яблоки Красный Делишес являются частью классификации яблоки, которая в свою очередь является частью класса фрукты, а тот — частью еще большего класса пища. Таким образом, класс пища обладает определенными качествами (съедобность, питательность и пр.), которые применимы и к подклассу фрукты. Помимо этих качеств, класс фрукты имеет специфические характеристики (сочность, сладость и пр.), которые отличают их от других пищевых продуктов. В классе яблоки определяются качества, специфичные для яблок (растут на деревьях, не тропические и пр.). Класс Красный Делишес наследует качества всех предыдущих классов и при этом определяет качества, которые являются уникальными для этого сорта яблок.
Если не использовать иерархическое представление признаков, для каждого объекта пришлось бы в явной форме определить все присущие ему характеристики. Но благодаря наследованию объекту нужно доопределить только те качества, которые делают его уникальным внутри его класса, поскольку он (объект) наследует общие атрибуты своего родителя. Следовательно, именно механизм наследования позволяет одному объекту представлять конкретный экземпляр более общего класса.
C++ и реализация ООП
В этой книге показано, что многие средства C++ предназначены для поддержки инкапсуляции, полиморфизма и наследования. Однако следует помнить, что язык C++ можно использовать для написания программ любого типа. Тот факт, что C++ поддерживает объектно-ориентированное программирование, не означает, что С++-программист может писать только объектно-ориентированные программы. Одним из самых важных достоинств языка C++ (как и его предшественника, языка С) является гибкость.
Связь C++ с языками Java и C#
Вероятно, многие читатели знают о существовании таких языков программирования, как Java и С#. Язык Java разработан в компании Sun Microsystems, a C# — в компании Microsoft. Поскольку иногда возникает путаница относительно того, какое отношение эти два языка имеют к C++, попробуем внести ясность в этот вопрос.
C++ является родительским языком для Java и С#. И хотя разработчики Java и C# добавили к первоисточнику, удалили из него или модифицировали различные средства, в целом синтаксис этих трех языков практически идентичен. Более того, объектная модель, используемая C++, подобна объектным моделям языков Java и С#. Наконец, очень сходно общее впечатление и ощущение от использования всех этих языков. Это значит, что, зная C++, вы можете легко изучить Java или С#. Схожесть синтаксисов и объектных моделей — одна из причин быстрого освоения (и одобрения) этих двух языков многими опытными С++-программистами. Обратная ситуация также имеет место: если вы знаете Java или С#, изучение C++ не доставит вам хлопот.
Основное различие между C++, Java и C# заключается в типе вычислительной среды, для которой разрабатывался каждый из этих языков. C++ создавался с целью написания высокоэффективных программ, предназначенных для выполнения под управлением определенной операционной системы и в расчете на ЦП конкретного типа. Например, если вы хотите написать высокоэффективную программу для выполнения на процессоре Intel Pentium под управлением операционной системы Windows, лучше всего использовать для этого язык C++.
Языки Java и C# разработаны в ответ на уникальные потребности сильно распределенной сетевой среды, которая может служить типичным примером современных вычислительных сред. Java позволяет создавать межплатформенный (совместимый с несколькими операционными средами) переносимый программный код для Internet. Используя Java, можно написать программу, которая будет выполняться в различных вычислительных средах, т.е. в широком диапазоне операционных систем и типов ЦП. Таким образом, Java-пpoгpaммa может свободно «бороздить просторами» Internet. C# разработан для среды .NET Framework (Microsoft), которая поддерживает многоязычное программирование (mixed-language programming) и компонентно-ориентированный код, выполняемый в сетевой среде.
Несмотря на то что Java и C# позволяют создавать переносимый программный код, который работает в сильно распределенной среде, цена этой переносимости — эффективность. Java-пpoгpaммы выполняются медленнее, чем С++-программы. То же справедливо и для С#. Поэтому, если вы хотите создавать высокоэффективные приложения, используйте C++. Если же вам нужны переносимые программы, используйте Java или С#.
И последнее. Языки C++, Java и C# предназначены для решения различных классов задач. Поэтому вопрос «Какой язык лучше?» поставлен некорректно. Уместнее задать вопрос по-другому: «Какой язык наиболее подходит для решения данной задачи?».

Комментирование и размещение ссылок запрещено.

Комментарии закрыты.