Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 21
Текст из файла (страница 21)
Стив Джонсон, тогдашний начальник отдела разработки С и С++, Дейв Каллман и я снова собрались и выработали план создания коммерческой версии 1.О. Однако практика прелоставления компилятора С++ (с исходными текстами и библиотеками) образовательным учреждениям «почти бесплатно», которая началась с версии Е, до сих пор жива. Версии С++ часто именуются по номерам версий С(гопп Версия 1.0 определена в книге «Язык программирования С++» 151гопзггцр, 1986]. В версиях 1.1 (июнь 1986 г.) и 1.2 (февраль 1987 г.) в основном исправлялись ошибки, сюда были также добавлены указатели на члены и защишенные члены (см. раздел 13.9).
В версии 2.0, вышедшей в июне 1989 г., компилятор подвергся существенной переработке. В нее же было включено множественное наследование (см. раздел 12.1). По обшему признанию, это был большой шаг вперед с точки зрения функциональности и качества. В версии 2.1 (апрель 1990 г.) ошибки преимущественно исправили, и С(гонг был (почти) приведен к определению, данному в книге «Тпе Аппотагеб С++ Ке(егепсе Манна!» [АКМ1 — см. раздел 5.3. В версии 3.0 (сентябрь 1991 г.) были добавлены шаблоны (см.
главу 15) в соответствии с определением АКМ. Вариант версии 3.0 с поддержкой исключений (см. главу 16) разработала и в конце 1992 г. выпустила на рынок компания Неъ1есг-Раскагд 1Сатегоп, 19921 ИИИИИИИВ Рождение С++ Сам я написал первые версии С(гонт (1.0, 1.1, 1.2) и сопровождал их. В течение нескольких месяцев перед выпуском версии 1.0 в 1985 г. со мной работал Стив Дьюхерст (5геуе ЕгетуЬцгш), Большую работу по написанию синтаксического анализатора для С(гоп! версий 1.0, 1.1, 2.1 и 3.0 проделала Лаура Иве ((лага Еауез). Я много слелал для версий 1.2 и 2.0, но, уже начиная с версии 1.2, достаточное время атой работе уделял Стэн Липпмап (5!ап (эрршап). Большую часть работы над версиями 2.1 и 3.0 проделали Лаура Иве, Стэн Липпман, Джордж Логотетис (Сеогйе 1лйогЬег!з), джуди уорд ([цг[! 'у!гагг[) и Нанси унлкинсон ()к!апсу %!Пс! пзоп). Работой над версиями 1.2, 2.0, 2.1 и 3.0 руководила Барбара Му. Энлрю Кениг организовал тестирование версии 2.0. Сэм Харадхвала (5аш Нагаг[Ьуа!а) нз компании ОЪ)ест Пез!8п 1пс.
выполи ил первую реализацию шаблонов в 1989 г., а Стэн Л иппман расширил и улучшил ее для версии 3.0 в 1991 г. Первая реализация обработки исключений лля С(гоп! выполнена компанией Неуг!егг-Рас[сагг[ в 1992 г. Помимо кола, вошедшего в основные версии С(гопц было создано и много локальных вариантов компилятора С++ на его базе. На протяжении нескольких лет такие компании, как Арр!е, Сепгег!!пе (бывшая 5аЬег), Сошеац Сошрцг!п8, О!ос!сепзр!е!, РагсР!асе, 5цп, Нету1егоРас[сагс[ и другие поставляли продукты, содержашие молифицированные версии С!гопп 3.4.
Возможности языка При переходе от С ту!гЬ С1авзез к С++ языку были добавлены следуюшие возможности: гз виртуальные функции (см. раздел 3.5); гэ перегрузка функций и операторов (см. раздел 3.6); гэ ссылки (см. раздел 3.7); гэ константы (см, раздел 3.8); гз контроль над распределением свободной памяти со стороны пользователя (см. раздел 3.9); ш улучшенный контроль типов (см. раздел 3.10). Кроме того, из языка изъяли функции са11 и гестаса (см. раздел 2.11), поскольку ими никто не пользовался, н внесли некоторые мелкие усовершенствования. 3.5. Виртуальные функции Самой яркой новой возможностью С++, оказавшей огромное влияние на стиль программирования, стали виртуальные функции.
Идея была заимствована из 5!пш1а, но модифицирована с целью сделать реализацию проша и эффективнее. Логическое обоснование виртуальных функций изложено в работах [5ггоцзсгцр, 1986) и [5тгоцз!гцр, 1986Ъ~. Для того чтобы подчеркнуть центральную роль виртуальных функций в программировании на С++, приведу развернутую цитату из [5!гоцзтгп р, 1986]; «Абстрактный тип данных — это кчерный ящикь.
Коль скоро он определен, объемлющая программа уже не может вмещаться в его работу. Единственный способ адаптировать его к нуждам ИИВИИИЕП Виртуальные функции нового пользователя — изменить определение. Это может быть причиной недостаточной гибко- сти. Рассмотрим тип вЬаре, предназначенный для систем работы с графикой. Предположим, что система должна поддерживать окружности, треугольники и квадраты и имеются следующие глассы: с1авв рогпг ( /*...*/ с1авв со1ог ( /*...*/ Можно было бы определить класс вЬаре таким образом: епци К1пс) ( сггс1е, Сг1апа1е, вс(ваге ); с1авв вЬаре ( роЫс сепсег; со1ог со1; К1пс) )с; // представление геометрической фигуры рць1(сг ро1пг ипего() ( гегцгп сепгегг ) ноЫ иоге(рогпс со) [ сепсег = со; с)гаи()г ) ноЫ с)гаи()г ноЫ госасе(Ыс); // другие операции )г ноЫ вЬаресгдгаи() ( виггсЬ (К) саве с1гс1е: // нарисовать окружность Ьгеа)сг саве сг1апа1ег // нарисовать треугольник Ьгеа)с; саве вс(цагег нарисовать квадрат ЬгеаК; Полная неразбериха! Функция вроде с)гам() должна «знать» обо всех типах фигур.
Позтому код такой функции растет при добавлении в систему каждой новой фигуры. Определив новую фип/ру, необходимо просмотреть и, возможно, модифицировать весь ранее написанный код Добавить новую фигуру не удастся, если исходный код недосгупен. Поскольку добавление новой фигуры затрагивает все важные операции над фигурами, от программиста требуется высокая квалификация, и все ровно не исключено, что в старый код будут внесены ошибки. Выбор представления конкретных фигур может серьезно усложниться, если требуется, чтобы оно, по крайней мере, частично соответствовало фиксированному образцу, принятому для обобщенного типа еЬаре. Поле типа К необходимо операциям типа с)гам ( ) и гас все ( ) дпя адекватного определения фигуры (в Ровса)-подобном языке можно было бы использовать вариантную запись с тягам К).
Тогда функция с)гам ( ) определялась бы так: ИИИИИИИВ Рождение С++ Проблема здесь в том, что между общими свойствами любой фигуры (она имеет цвет, может быть нарисовано и т.д.) и свойствами конкретной фигуры (окружность — это фигура, которая имеет радиус, прорисовывается функцией вычерчивания окружности и т.д.) нет четкого разграничения. Возможность выразить такое разграничение и воспользоваться им составляет суть обьектно-ориентированного программирования. Язык, обладающий такими выразительными возможностями, поддерживает обьектно-ориентированное программирование. Остальные языки его не поддерживают.
Механизм наследования в б)гпч!а предлагает решение, которое я принял на вооружение в Сь». Сначало мы описываем класс, в котором определены общие свойства всех фигур; с1авв впаре ( рогат сепсег; со1от со1; // рцЫ(с: рогпс н)гете() ( гесптп сепсегт ) чо1й нече(ратас со) ( сепсег = со; йтан(); ) чггсивь чогд дтан(); ч(гтца1 чозй гагате(гпС); Все функции, для которых можно определить порядок вызова, но пел~за предоставить реализацию для фигуры общего вида, помечены словом чьтспа 1 (общий для 5)глч)о и Сь» термин, означающий «может быть переопределена в классе, производном от данного»).
Имея донное определение, для манипуляций с фигурами можно написать обобщенные функции: чотй тосасе а11(в)гаре** ч, (пс в1зе, (пс апд1е) // повернуть все элементы вектора ч размера в1зе // на апд1е градусов гот (ьпс 1 = От 1 < з(ге; 1++) ч(1] г»тосасе(апд1е) т ) Чтобы определить конкретную фигуру, нужно сформулировать, чту это за фигура и задать ее специфические свойства, в том числе виртуальные функции. с1авв с1тс1е: рцЫьс в)гаре ( 1пс гай1цв; рцЫ1с: чогй йган() ( /* ...
*/ чогй тосасе(гпс) () // да, зго пустая функция В Сьт говорят, что класс с 1 го 1е является производным от в)гаре, а класс в)таре — базовый для сьгс1е. В)слугой терминологии сггс1е и в)таре называются соответственно подклассом и суперклассом». Дальнейшее обсуждение виртуальных функций и объектно-ориентированного программирования см.
в разделах 13.2, 12.3.1, 13.7, 13.8 и 14.2.3. Насколько я помню, в то время виртуальные функции не вызвали большого интереса. Возможно, я недостаточно хорошо объяснил заложенные в них концепции, но преобладаюшей реакцией в кругу близких мне людей было безразличие и скептипизм. Обшее мнение сводилось к тому, что виртуальные функции — зто ИИИИИИИП Виртуальные функции 3.5.1 Модель размещения обьекта в памяти Ключевая идея реализации состояла в том, что множество виртуальных функций класса определяет массив указателей на функции, поэтому вызов виртуальной функции — это просто косвенный вызов функции через данный массив. Для каждого класса с виртуальными функциями имеется ровно один такой массив, который обычно называют таблицей виртуальных функций или чс)з1.