
- •1. Дополнения к с
- •1.1. Комментарии
- •1.2. Ключевые слова
- •1.3. Константы
- •1.4. Блочные объявления
- •1.5. Ссылки
- •1.6. Новая роль имён перечислений, структур и объединений
- •1.7. Распределение памяти
- •1.8. Встраиваемые функции
- •1.9. Перегрузка функций
- •1.10. Задание для параметров функции значений по умолчанию
- •1.11. Дополнительные операции для доступа к данным
- •1.12. Предопределённые потоки ввода-вывода
- •2.1. Инкапсуляция
- •2.2. Разграничение доступа (скрытие данных и методов)
- •2.3. Друзья классов
- •2.4. Конструкторы и деструкторы
- •2.5. Конструктор по умолчанию
- •2.6. Конструктор копирования
- •2.7. Несколько слов о деструкторах
- •2.8. Перегрузка операций
- •3.1. Наследование
- •3.2. Виртуальные функции –полиморфизм
- •3.3. Шаблоны
2.1. Инкапсуляция
Для
определения классов используются три
ключевых слова: struct, union и class. Каждый
класс, определённый посредством одного
из этих ключевыхслов,
включает в себя функции –называемые
методами или
компонентными
функциями (member function), и данные
–называемыеэлементами данных (class
members). Так же, как и для структур и
объединений, каждому классу
присваивается некоторое имя (лучшесодержательное),
которое становится идентификатором
нового типа данных и может
использоваться для объявленияобъектов
(илиэкземпляров)
этоготипа
(рис 2.1).
Рис. 2.1. Инкапсуляция элементов и методов класса
Описание класса начинается с ключевого слова ключ_класса, в качестве которого можно использовать слова struct, union, class, и непосредственно за которым следует имя класса – имя_класса:
ключ_класса имя_класса <: базовый_список>
{
< Компоненты_класса > // Здесь объявляются как методы, так и элементы класса
};
Необязательный базовый_список содержит базовый класс (или классы), из которогоимя_класса заимствует элементы и методы. Необязательный список компонентов объявляет элементы и методы класса и, при необходимости, спецификаторы доступа.
После того как объявлен новый уникальный тип данных, можно определять объекты данного типа класса, а также объекты, являющиеся производными от него:
class Sample{
unsigned uData; // Элемент данных
unsigned ReadData( ); // Метод (компонентная функция)
. . .
};
Sample clInst1, // Переменная типа Sample
*pclInst2 = &clInst1, // Указатель на Sample arInst [7]; // Массив элементов типа Sample
Допускаются также неполные объявления класса:
class Sample;
которые разрешают некоторые ссылки к именам классов до того, как классы будут полностью определены.
Обращаться к компонентам класса можно указав имя объекта – имя элемента или метода, и разделив эти имена операцией . (точка), или, при использовании указателя – операцией ->:
Пример 2.1
clInst1.uData = 7;
unsigned uRes = pcInst2->ReadData ( );
Примечание
Несмотря на то, что приведенные выражения правильны, при компиляции будет выдано сообщение об ошибке, поскольку в соответствии с принципом скрытия данных, установленным по умолчанию, доступ и к элементу данных и к методу невозможен.
Чуть раньше уже упоминалось о том, что в С++ возможно встраивание функций посредством спецификатора inline, который является не больше чем «просьбой» к компилятору, которую он может как удовлетворить, так и проигнорировать.
Для методов класса возможно неявное выражение такой просьбы:
class MyClass{
... // объявление переменных и методов
float fVar;
float * func ( ); { return fVar; } // inline по умолчанию
};
что эквивалентно следующей записи:
inline float * MyClass :: func ( ); { return fVar; }
Очевидно, что к встраиваемым функциям понятие адреса неприменимо. В отличие от обычных функций языка С (да и С++ тоже), нестатические методы классов в С++ имеют одну неявную локальную переменную. Эта переменная даже имеет специальное имя – this. И хотя на практике она используется достаточно редко, в некоторых случаях наличие этой переменной бывает полезно, в чём мы скоро убедимся на примерах. Фактически, this – это указатель на текущий объект класса.
Употреблённое выше слово «нестатические» требует некоторых пояснений.
При объявлении данных и методов класса может быть использован спецификатор класса памяти static. Вспомните, что в С++ этот спецификатор ограничивает область видимости переменной или функции одним модулем – налицо попытка введения некоторого ограничения доступа. Компоненты, перед которыми стоит это ключевое слово, называются статическими и обладают свойствами, отличными от свойств «обычных» элементов. Для наглядности рассмотрим небольшой пример:
class MyClass {
int nVarUnStatic; // обычная переменная
static int VarStatic; // статическая переменная
// объявления других переменных и методов
};
MyClass clInstance1, *pclInstance2;
Рис. 2.2. Распределение памяти для статических и нестатических переменных
Таким образом, в случае нестатических (обычных) элементов для каждого объекта класса создается отдельная копия и обращение, например, к. элементу nVarUnStatic осуществляется по обычным правилам:
clInstasnce1.nVarUnStatic++; // правильно
pclInstance2->nVarUnStatic++; // правильно
а для статического элемента можно просто задать имя класса совместно с модификатором области действия:
MyClass :: nVarStatic++; // правильно
Однако это еще не всё. В отличие от нестатических элементов, память под которые выделяется при создании объекта класса, для статических должно существовать отдельное определение, отвечающее за распределение памяти и инициализацию, например, такое:
static MyClass :: nVarStatic;
Основное назначение статических элементов состоит в том, чтобы отслеживать данные, общие для всех объектов класса, а также для уменьшения числа видимых глобальных имен.
По аналогии со статическими элементами данных, статические методы не ассоциируются с каким-либо конкретным объектом и, соответственно, не имеют указателя this. Такие методы вызываются просто по имени класса, например, так:
MyClass :: Func ( );
Поскольку статический метод не имеет указателя this, из него нельзя обращаться к элементам данных, не задавая в явном виде конкретный объект. В то же время допустимо непосредственное обращение к статическим компонентам класса. Осталось сказать еще о двух ограничениях:
– Нельзя определять нестатический метод с тем же именем и тем же набором параметров, что и у статического метода класса.
– Статический метод не может быть объявлен как виртуальный (о виртуальных методах мы поговорим чуть позже).
Примечание
Для элементов данных и методов класса недопустимо использование каких-либо других спецификаторов класса памяти кроме static.
В языке С++ разграничение доступа получило свое логическое продолжение. Рассмотрим этот вопрос более подробно.