Управление доступом к переменным и методам класса

      Комментарии к записи Управление доступом к переменным и методам класса отключены

Для переменных и методов класса может быть задан уровень доступа, регламентирующий доступ к переменным и методам одного класса из методов другого класса. Наиболее жестким является личный уровень доступа, дающий разрешение на доступ к переменным и методам только для методов самого класса. Наименее жестким – общий уровень доступа, дающий разрешение на доступ из любой точки программы. Средним вариантом является личный защищенный уровень доступа, когда доступ разрешен только для методов самого класса и его наследников. Уровень доступа в классе-потомке к переменной или методу класса-предка может быть изменен в сторону ужесточения. В зависимости от языка программирования промежуточные уровни доступа могут различаться. Так, например, в Java существует два дополнительных уровня доступа. В случае нарушения программистом регламента доступа к переменным во время компиляции программы будет выдано сообщение об ошибке. Приведем пример задания уровней доступа для переменных класса на языке C++:

class Person {private: — Личный уровень доступаint number; — Индивидуальный номер человекаpublic: — Общий уровень доступаchar name[10]; — Имяprotected: — Личный защищенный уровень доступаint age; — Возрастfloat height; — Рост};

В объектно-ориентированных языках программирования существуют механизмы описания исключений из перечисленных правил доступа. Первый механизм заключается в объявлении дружественности класса. Если некоторый класс A объявлен как дружественный некоторому классу B, то все методы A могут обращаться ко всем методами и переменным класса B, независимо от их уровня доступа. Например,

class B {…friend class A; — Объявление дружественного класса.};

Второй механизм позволяет объявлять лишь некоторые методы класса A как дружественные классу B. Это приводит к возможности обращаться ко всем переменным и методам класса B, независимо от заданного для них уровня доступа, только в рамках этих методов. Например,

class B {…friend A::methodX; — Объявление дружественного метода};

Интерфейс

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

class Interchanger {virtual int get ()=0;virtual void put ()=0;};

Исключения

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

— Необходимость поддержания списка констант со всеми возможными кодами результата.

— Необходимость при вызове каждого метода проверять возвращаемое им значение. При этом, программа превращается в наслоение множества вложенных if или switch-операторов, теряется ее читабельность.

Этот подход можно проиллюстрировать на таком примере:

if (methodA()ERROR) {if (methodB()ERROR) {…}else {}else {}

От перечисленных недостатков свободен второй механизм сообщения о критических ошибках – механизм исключений. Исключение представляет собой механизм обработки ошибочных ситуаций без использования кодов возврата из метода и включает в себя два аспекта: аспект описания обработки исключений и аспект генерации исключений.

Для описания обработки исключений программист определяет в рамках метода три типа блоков операторов: блок испытания, блок обработки исключений, финальный блок. Блок испытания объявляется с использованием ключевого слова try. Непосредственно за блоком испытаний следует один или несколько блоков обработки, объявляемых ключевым словом catch и, при необходимости, один финальный блок, объявляемый ключевым словом finally. Блок обработки может иметь одну переменную в качестве параметра. При генерации исключения обязательно указывается переменная, значение которой является параметром исключения. Генерация исключения осуществляется при помощи ключевого слова throw. Приведем пример описания обработки исключений на языке С++:

try {methodA();methodB();}catch (Error e) {…}finally {…}

Если сравнить этот пример с предыдущим, то наглядно видно, что второй механизм обработки исключений приводит к более читабельному коду программы. Особенно, если блок try достаточно большой (при использовании первого механизма мы получили бы операторы ветвления очень большой вложенности).

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

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

Пунктирная линия показывает логический переход к вышестоящему блоку испытания в результате генерации исключения.

Если некоторый блок является корневым, то есть для него не существует вышестоящих, то будет выполнен обработчик исключений по умолчанию, который выдаст содержимое параметра исключения и завершит работу программы.

Поиск блока обработки по типу параметра исключения происходит последовательно, в порядке их описания. Поэтому блоки обработки, входные переменные которых имеют тип классов-потомков, должны идти раньше блоков обработки классов-предков. Иначе они никогда не будут выполняться. Последним блоком обработки может идти блок без входной переменной. Такой блок обрабатывает все исключения с любыми параметрами.

Во всех объектно-ориентированных языках существует специальный синтаксис оператора throw, позволяющий в рамках любого обработчика исключений повторить генерацию обрабатываемого исключения. В этом случае не требуется явно указывать переменную исключения в качестве параметра – автоматически будет использована текущая переменная. При этом перед тем, как сгенерированное исключение будет передано вышестоящему блоку испытания, обязательно будет выполнен финальный блок для текущего блока испытания. Проиллюстрируем это.

Если в ходе исполнения блока испытания ни один из операторов не привел к генерации исключения – будет выполнен финальный блок из совокупности блоков исключений, а затем выполнение метода продолжится с того оператора, который следует после совокупности блоков исключений.

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

В момент начала выполнения вложенного блока испытания срабатывает встраиваемый код, отмечающий в стеке начало следующего фрейма исключения. В момент завершения выполнения – эта метка снимается. В результате образуется стек фреймов путем логического разделения стека переменных на части. Например, для следующего программного кода на языке C++:

try { — Начало фрейма Xint x, y, z;try { — Начало фрейма Yint a, b, c;… — Точка P} catch (…) {…}} catch (…) {…}

в точке P стек переменных и фреймов будет представлять собой следующее:

Когда выполнение некоторого блока испытания прерывается исключением, все переменные входящие в его фрейм удаляются из стека, что приводит к автоматическому откату всех методов, вызванных в этом блоке (любой степени вложенности). Далее на вершину стека помещается параметр исключения и по специальным структурам осуществляется поиск необходимого блока обработки (соответствующего текущему блоку испытания, данные о котором хранятся в метке фрейма исключения, снятого с вершины стека). Если блок обработки найден – передается управление ему, если не найден – с вершины стека снимается очередной фрейм. В конце каждого обработчика встраивается код, выполняющий поиск и выполнение финального блока для текущего блока испытания, а также переход к оператору метода, следующему за совокупностью блоков исключений. Одновременно, в конце каждого блока испытания встраивается вызов финального блока и переход на оператор метода, следующий после блоков исключений. Это приводит к тому, что при выполнении блока испытания без генерации исключений исполняется финальный блок и работа метода продолжается.

Шаблоны

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

template class Entity {A var1;B var2;};

Шаблоны классов используются так же, как и классы, с тем отличием, что для них обязательно указываются типы переменных, которые необходимо использовать в качестве параметров шаблона. Например, для того, чтобы объявить переменную e класса Entity с параметрами типа int и float необходим следующий программный код:

Entity e;

Новый класс конструируется в ходе компиляции в тот момент, когда использование шаблона с заданным сочетанием параметров встречается в первый раз. Для каждого сочетания параметров шаблона будет создан свой собственный класс. Далее, когда данный шаблон с тем же сочетанием параметров будет встречен компилятором повторно, будет использован ранее сгенерированный класс. Таким образом, в процессе компиляции для шаблона Entity может быть создано большое количество классов:

Далее рассмотрим второй вид шаблонов: шаблон функции. Шаблон функции, как и шаблон класса, имеет один или несколько параметров, которые могут использоваться в теле функции подобно типам. В ходе компиляции из шаблона функции конструируются функции – по одной для каждого сочетания параметров шаблона, встреченного в исходном тексте программы. При этом параметры шаблона заменяются на конкретные типы по всему телу функции. Например, шаблоном функции на языке C++ является:

template T Mid (T x, T y) { return (x+y)/2; }

Данный шаблон может быть использован посредством указания конкретного типа в качестве его параметра:

float x=Mid (a, b);

В ходе компиляции для этого шаблона могут быть созданы, например, следующие функции:

Статьи к прочтению:

80. Доступ к private переменным класса в Java [300+ questions]


Похожие статьи:

  • Взаимодействие методов по управлению

    МЕТОДЫ В различных языках программирования имеются термины, которые по сути означают одно и то же понятие. Например, подпрограмма,…

  • Методы доступа к сетевому ресурсу

    Для использования сетевого ресурса необходимо получить доступ к нему. Существуют три метода доступа: множественный доступ с контролем несущей, доступ с…