Мюррей Хилл - C++
- Название:C++
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Мюррей Хилл - C++ краткое содержание
С++ – это универсальный язык программирования, задуманный так, чтобы сделать программирование более приятным для серьезного программиста. За исключением второстепенных деталей С++ является надмножеством языка программирования C. Помимо возможностей, которые дает C, С++ предоставляет гибкие и эффективные средства определения новых типов. Используя определения новых типов, точно отвечающих концепциям приложения, программист может разделять разрабатываемую программу на легко поддающиеся контролю части. Такой метод построения программ часто называют абстракцией данных. Информация о типах содержится в некоторых объектах типов, определенных пользователем. Такие объекты просты и надежны в использовании в тех ситуациях, когда их тип нельзя установить на стадии компиляции. Программирование с применением таких объектов часто называют объектно-ориентированным. При правильном использовании этот метод дает более короткие, проще понимаемые и легче контролируемые программы.
Ключевым понятием С++ является класс. Класс – это тип, определяемый пользователем. Классы обеспечивают сокрытие данных, гарантированную инициализацию данных, неявное преобразование типов для типов, определенных пользователем, динамическое задание типа, контролируемое пользователем управление памятью и механизмы перегрузки операций. С++ предоставляет гораздо лучшие, чем в C, средства выражения модульности программы и проверки типов. В языке есть также усовершенствования, не связанные непосредственно с классами, включающие в себя символические константы, inline-подстановку функций, параметры функции по умолчанию, перегруженные имена функций, операции управления свободной памятью и ссылочный тип. В С++ сохранены возможности языка C по работе с основными объектами аппаратного обеспечения (биты, байты, слова, адреса и т.п.). Это позволяет весьма эффективно реализовывать типы, определяемые пользователем.
С++ и его стандартные библиотеки спроектированы так, чтобы обеспечивать переносимость. Имеющаяся на текущий момент реализация языка будет идти в большинстве систем, поддерживающих C. Из С++ программ можно использовать C библиотеки, и с С++ можно использовать большую часть инструментальных средств, поддерживающих программирование на C.
Эта книга предназначена главным образом для того, чтобы помочь серьезным программистам изучить язык и применять его в нетривиальных проектах. В ней дано полное описание С++, много примеров и еще больше фрагментов программ.
C++ - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Когда описывается производная struct, ее базовый класс по умолчанию является public базовым классом. То есть,
struct D : B (* ...
означает
class D : public B (* public: ...
Отсюда следует, что если вы не сочли полезным то сокртие данных, которое дают class, public и friend, вы можете просто не использовать эти ключевые слова и придерживаться struct. Такие средства языка, как функции члены, конструкторы и перегрузка операций, не зависят от механизма сокрытия даных.
Можно также объявить некоторые, но не все, открытые члны базового класса открытыми членами производного класса. Например:
class manager : employee (* // ... public: // ... employee::name; employee::department; *);
Запись
имя_класса :: имя_члена ;
не вводит новый член, а просто делает открытый член бзового класса открытым для производного класса. Теперь name и department могут использоваться для manager'а, а salary и age – нет. Естественно, сделать закрытый член базового класса окрытым членом производного класса невозможно. Невозможно с помощью этой записи также сделать открытыми перегруженные имена.
Подытоживая, можно сказать, что вместе с предоставлением средств дополнительно к имеющимся в базовом классе, произвоный класс можно использовать для того, чтобы сделать средства (имена) недоступными для пользователя. Другими словами, с пмощью производного класса можно обеспечивать прозрачный, плупрозрачный и непрозрачный доступ к его базовому классу.
7.2.4 Указатели
Если производный класс derived имеет открытый базовый класс base, то указатель на derived можно присваивать перменной типа указатель на base не используя явное преобразовние типа. Обратное преобразование, указателя на base в указтель на derived, должно быть явным. Например:
class base (* /* ... */ *); class derived : public base (* /* ... */ *);
derived m; base* pb = amp;m; // неявное преобразование derived* pd = pb; // ошибка: base* не является derived* pd = (derived*)pb; // явное преобразование
Иначе говоря, объект производного класса при работе с ним через указатель и можно рассматривать как объект его бзового класса. Обратное неверно.
Будь base закрытым базовым классом класса derived, неяное преобразование derived* в base* не делалось бы. Неявное преобразование не может в этом случае быть выполнено, потому что к открытому члену класса base можно обращаться через укзатель на base, но нельзя через указатель на derived:
class base (* int m1; public: int m2; // m2 – открытый член base *);
class derived : base (* // m2 – НЕ открытый член derived *);
derived d; d.m2 = 2; // ошибка: m2 из закрытой части класса base* pb = amp;d; // ошибка: (закрытый base) pb-»m2 = 2; // ok pb = (base*) amp;d; // ok: явное преобразование pb-»m2 = 2; // ok
Помимо всего прочего, этот пример показывает, что ипользуя явное приведение к типу можно сломать правила защиты. Ясно, делать это не рекомендуется, и это приносит программиту заслуженную «награду». К несчастью , недисциплинированное использование явного преобразования может создать адские уловия для невинных жертв, эксплуатирующих программу, в котрой это делается. Но, к счастью, нет способа воспользоваться приведением для получения доступа к закрытому имени m1. Зарытый член класса может использоваться только членами и друзьями этого класса.
7.2.5 Иерархия Типов
Производный класс сам может быть базовым классом. Например:
class employee (* ... *); class secretary : employee (* ... *); class manager : employee (* ... *); class temporary : employee (* ... *); class consultant : temporary (* ... *); class director : manager (* ... *); class vice_president : manager (* ... *); class president : vice_president (* ... *);
Такое множество родственных классов принято называть ирархией классов. Поскольку можно выводить класс только из оного базового класса, такая иерархия является деревом и не может быть графом более общей структуры. Например:
class temporary (* ... *); class employee { ... *); class secretary : employee (* ... *);
// не С++: class temporary_secretary : temporary : secretary(* ... *); class consultant : temporary : employee (* ... *);
И этот факт вызывает сожаление, потому что направленный ациклический граф производных классов был бы очень полезен. Такие структуры описать нельзя, но можно смоделировать с пмощью членов соответствующих типов. Например:
class temporary (* ... *); class employee (* ... *); class secretary : employee (* ... *);
// Альтернатива: class temporary_secretary : secretary (* temporary temp; ... *); class consultant : employee (* temporary temp; ... *);
Это выглядит неэлегантно и страдает как раз от тех пролем, для преодоления которых были изобретены производные классы. Например, поскольку consultant не является произвоным от temporary, consultant'а нельзя помещать с список врменных служащих (temporary employee), не написав специальный код. Однако во многих полезных программах этот метод успешно используется.
7.2.6 Конструкторы и Деструкторы
Для некоторых производных классов нужны конструкторы. Если у базового класса есть конструктор, он должен вызыватся, и если для этого конструктора нужны параметры, их надо предоставить. Например:
class base (* // ... public: base(char* n, short t); ~base(); *);
class derived : public base (* base m; public: derived(char* n); ~derived(); *);
Параметры конструктора базового класса специфицируются в определении конструктора производного класса. В этом смысле базовый класс работает точно также, как неименованный член производного класса (см. #5.5.4). Например:
derived::derived(char* n) : (n,10), m(«member»,123) (* // ... *)
Объекты класса конструируются снизу вверх: сначала базвый, потом члены, а потом сам производный класс. Уничтожаются они в обратном порядке: сначала сам производный класс, потом члены а потом базовый.
7.2.7 Поля Типа
Чтобы использовать производные классы не просто как удобную сокращенную запись в описаниях, надо разрешить следющую проблему: Если задан указатель типа base*, какому проиводному типу в действительности принадлежит указываемый обект? Есть три основных способа решения этой проблемы:
1. Обеспечить, чтобы всегда указывались только объекты одного типа (#7.3.3),
2. Поместить в базовый класс поле типа, которое смогут просматривать функции и
3. Использовать виртуальные функции (#7.2.8).
Обыкновенно указатели на базовые классы используются при разработке контейнерных (или вмещающих) классов: множество, вектор, список и т.п. В этом случае решение 1 дает однородные списки, то есть списки объектов одного типа. Решения 2 и 3 можно использовать для построения неоднородных списков, то есть списков объектов (указателей на объекты) нескольких раличных типов. Решение 3 – это специальный вариант решения 2 с гарантией типа.
Давайте сначала исследуем простое решение с помощью поля типа, то есть решение 2. Пример со служащими и менеджерами можно было бы переопределить так:
enum empl_type (* M, E *);
struct employee (* empl_type type; employee* next; char* name; short department; // ... *);
struct manager : employee (* employee* group; short level; // уровень *);
Имея это, мы можем теперь написать функцию, которая пчатает информацию о каждом служащем:
void print_employee(employee* e) (* switch (e-»type) (* case E: cout «„ e-“name „„ „\t“ „„ e-“department „„ „\n“; // ... break; case M: cout „« e-“name «« «\t“ «« e-“department «« «\n“; // ... manager* p = (manager*)e; cout «« " уровень " «« p-“level «« «\n“; // ... break;
Читать дальшеИнтервал:
Закладка: