Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык программирования С++ и его «подводные камни».DOC
Скачиваний:
44
Добавлен:
01.05.2014
Размер:
1.02 Mб
Скачать

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.

В языке С++ разграничение доступа получило свое логическое продолже­ние. Рассмотрим этот вопрос более подробно.