Опубликован: 06.10.2011 | Доступ: свободный | Студентов: 1678 / 90 | Оценка: 4.67 / 3.67 | Длительность: 18:18:00
Дополнительный материал 3:

Введение в C++ (по материалам Надежды Поликарповой)

Общепринято характеризовать ОО-языки как "чистые" (полностью и исключительно реализующие ОО-концепции) либо как "гибридные" (представляющие смесь объектных и необъектных свойств). Наиболее известным представителем гибридных языков является язык С++, который создавался с целью предоставления С-программистам некоторых ОО-идей и механизмов. Язык С++ по духу отличается от нотации Eiffel, принятой в остальной части книги, и более сложен.

Можно найти много книг и вводных статей о С++, как начинающихся с чистого листа, так и предполагающих знание языка С. Роль этого приложения другая: она ориентирована именно на вас, внимательных читателей этой книги, кто прочел уже сотни страниц и овладел ОО-программированием в его "чистой" форме. Цель в том, чтобы в случае необходимости программирования на С++ применять его конструкции в духе Eiffel. По этой причине многие конструкции C++ будут объясняться - как это сделано для Java и C# - в стиле: "Вот как это можно сделать на Eiffel и как получить такой же эффект на С++".

Язык С, на котором основан С++, сам является важным языком, кратко рассматриваемым в следующем приложении.

Основы языка и стиль

Сегодня идея использования ОО-языка едва ли может удивить кого-либо, но в конце восьмидесятых годов она воспринималась как насмешка, - многим программистам и менеджерам в индустрии и академических кругах ОО-концепции казались привлекательными, но возникали большие сомнения в их применимости. В 1979 году Бьёрн Страструп из Bell

 Бьёрн Страуструп (2007)

Рис. 13.1. Бьёрн Страуструп (2007)

Laboratories спроектировал и реализовал язык, изначально названный "С с классами", расширяющий язык С концепциями, которые были заимствованы у языка Simula 67, - первого ОО-языка. Код транслировался в чистый С препроцессором. Язык вскоре стал хитом и, как было обещано, облегчил переходный период для С-программистов.

В следующие два десятилетия язык интенсивно развивался за счет введения таких конструкций, как шаблоны (форма универсальности) и множественное наследование.

Общая организация программ

Для ОО-подхода программа представляет множество классов. В С++, сохраняющем гибридный дух, не настаивают на соблюдении этого правила. Программа может включать классы, но и другие элементы, не входящие в классы: функции (соответствующие методам, реализуемым либо в виде настоящих функций, либо в виде процедур), переменные, константы и типы, не заданные классами.

Примером независимой функции, появляющейся в каждой исполняемой программе, является функция, называемая main, которая определяет точку входа в программу. В Eiffel эту роль играет корневая процедура создания.

Программная система на С++ представляет скорее не множество классов, а множество единиц трансляции (юнитов или модулей), каждая из которых содержится в отдельном файле, который независимо может быть обработан С++ компилятором. Каждая единица трансляции может содержать объявления классов и других типов, функций, переменных и констант.

Объявление такого элемента может быть его определением, означающим его полное описание, либо может объявлением, не задающим определение, таким как:

class Person; 
enum Week_day;

При этом понимается, что полное определение этого элемента (здесь класс и тип) появится либо в другом модуле, либо в той же единице, но позже. Это дает возможность использовать элемент без знания его детальных свойств. Для переменной или константы неопределяющее объявление использует ключевое слово extern, указывающее, что определение еще появится:

extern bool has_error; 
extern const double pi;

Определение функции включает имя, сигнатуру и реализацию:

int factorial (int n) 
    {
      if (n > 1) {
        return n _ factorial (n - 1); 
      } else {
        return 1; 
      } 
    }

Определение класса содержит список членов класса (компонентов):

class Person { // Объекты, представляющие персон 
    string name; // Имя персоны 
    Date birth_date; // Дата рождения 
    void set_name (string s)
     {name = s;} 
    void set_birth_date (Date d)
     {birth_date = d;} 
    … // Другие члены класса 
 };

В определении переменной задается ее тип, предшествующий переменной в отличие от Eiffel, где действует соглашение variable_name: TYPE.

int n;
bool has_error = false;

Второе из этих объявлений содержит инициализацию переменной, устанавливающую ее начальное значение. Определения не содержат extern: это означает, что переменные не являются внешними, а значит, могут использоваться только в данном модуле трансляции.

Определение переменной означает, что ей будет отведена память, как для развернутых типов Eiffel.

Определение константы всегда включает ее инициализацию:

const double Pi = 3.14159265358

В отличие от Eiffel порядок объявлений существенен: имена, объявленные в модуле трансляции, можно использовать только после точки объявления. Для применения элемента до его определения - такая необходимость возникает, например, в случае множества взаимно рекурсивных определений - предварительно следует задать неопределяющее объявление.

Во избежание трансляции слишком большого модуля можно разделить его на несколько файлов, используя затем директиву включения #include, как в примере:

#include "filename"

Как результат, все определения, содержащиеся в исходном файле filename, будут доступны текущему модулю трансляции. Чаще всего это свойство предполагает использование заголовочных файлов (по соглашению имеющих имена в форме name.h), которые содержат объявления элементов, используемых многими модулями, и включают соответствующую директиву #include.

Директива #include, подобно любым другим предложениям, начинающимся с символа решетки #, адресована препроцессору С++ - инструментарию, обрабатывающему файлы программы до начала компиляции. Другое использование препроцессора связано с условной компиляцией, позволяющей определять препроцессорные переменные и включать в выполнение некоторый код только при условии задания соответствующих переменных. Вот типичный пример:

#ifdef LINUX
     … Linux-specific code … 
#endif

Код для платформы Linux будет подключен в зависимости от LINUX-переменной. Такие переменные, не связанные с переменными программы, рассматриваются как опции, действующие на этапе работы препроцессора и компилятора.