Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Интерфейс и состояние объекта




Лекция № 4.

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

 

Помимо раздельных определения функции-члена в классе и последующей её реализации (как было приведено выше) можно реализовать функцию непосредственно в рамках определения класса:

 

class Complex {public: int real; // вещественная часть int imaginary; // мнимая часть // прибавить комплексное число void Add(Complex x) { real = real + x.real; imaginary =imaginary + x.imaginary; }};

 

Конструкторы классов

 

Объекты нельзя инициализировать так, как это возможно делать для обыкновенных типов данных.

 

int i=1; // верно

Struct tColor

{

int r;int g;int b;

};

tColor color={255,0,0}; // верно

Complex number={10,6}; // не верно!!!

 

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

Существуют специальные функции, получившие названия конструкторов и деструкторов, которые обычно резервируются за каждым классом. Конструкторы как раз решают задачу инициализации объекта.

Функция-конструктор выполняется каждый раз, когда создается новый объект этого класса. Конструктор – это метод, имя которого совпадает с именем класса. Конструктор не возвращает никакого значения.

Конструктор без аргументов называется стандартным конструктором или конструктором по умолчанию. Такой конструктор используется при объявлении такого вида:

Complex number;

Конструктор по умолчанию используется всегда, если для класса не определен никакой другой конструктор. Как только программист определяет свой конструктор, то при создании экземпляра класса этот конструктор и вызывается.

Определим для нашего класса следующий конструктор.

Зададим прототип конструктора:

Complex(int p1,int p2); Реализация конструктора: Complex::Complex(int p1,int p2){ real=p1; imaginary=p2;}

Теперь создаем и инициализируем с помощью конструктора объект Complex.

Complex number(10,5);

Однако что делать, если мы не всегда хотим инициализировать объект при его создании? Можно создать дополнительно к нашему созданному конструктору еще один конструктор – пустой.

Прототип конструктора:

Complex(); Реализация конструктора: Complex::Complex(){}

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

Итак, наш класс Complex теперь будет выглядеть следующим образом

class Complex {public: int real; // вещественная часть int imaginary; // мнимая часть Complex(); // конструктор 1 Complex(int p1,int p2);// конструктор 2 // прибавить комплексное число void Add(Complex x); };

 

Деструкторы классов

 

В отличие от конструктора, который вызывается для инициализации объекта при его создании, деструктор является полной противоположностью конструктора.

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

Например, если ваш конструктор использует спецификатор new для выделения памяти, то деструктор с помощью оператора delete освобождает эту занятую па­мять.

Как и конструктор, деструктор имеет специальное имя: имя класса, которому пред­шествует тильда (~). Добавим для нашего класса Complex деструктор.

Прототип деструктора:

~Complex(); Поскольку у деструктора класса Complex нет никаких важных обязанностей, мы можем закоди­ровать его как функцию, которая не выполняет никаких действий. Итак, реализация деструктора будет следующая: Complex::~Complex(){}

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

Complex::~Complex(){

cout «"Bye!\n";

}

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

 

Интерфейс и состояние объекта

 

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

Определение класса можно поделить на три части –

ü внешнюю,

ü внутреннюю,

ü защищенную.

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

Определением внешней части мы контролируем способ обращения к объекту.

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

 

class String{ public: //добавить строку в конец текущей строки void Concat(const String str); // заменить заглавные буквы на строчные void ToLower(void); // сообщить длину строки int GetLength(void) const;...};

Внутренняя и защищенная части класса доступны только при реализации методов этого класса, а также так называемымми функциями-“друзьями” класса.

Внутренняя часть предваряется ключевым словом private. Для всех переменных-членов и методов, описанных с атрибутом Private, – доступ открыт только самому классу (т.е. функциям-членам данного класса) и так называемым друзьям (friend) данного класса, как функциям, так и классам.

Защищенная часть описывается ключевым словом protected. В отличие от внутренней части (private), элементы защищенной части (protected) также могут быть доступны и для методов и функций классва, для которых данный класс является базовым, то есть, для производных классов при наследовании. То есть, если мы хотим, чтобы какая-то функция класса была доступна его потомку при реализации наследования, то она может быть описана с атрибутом protected.

Ключевые слова public, private, protected называются атрибутами доступа при описании классов.

Рассмотрим пример использования атрибутов доступа.

 

class String{ public: //добавить строку в конец текущей строки void Concat(const String str); //заменить заглавные буквы на строчные void ToLower(void); // сообщить длину строки int GetLength(void) const; private: char* str; int length;};

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

Объявляя атрибуты str и length как private, мы говорим, что непосредственно к ним обращаться можно только при реализации методов класса, как бы изнутри класса.

Например:

int String::GetLength(void) const{ return length;}

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

Реализация метода Concat будет выглядеть следующим образом:

void String::Concat(const String x){ length += x.length; char* tmp = new char[length + 1]; strcpy(tmp, str); strcat(tmp, x.str); delete [] str; str = tmp;}

Однако если в программе будет предпринята попытка обратиться к внутреннему атрибуту или методу класса вне определения метода, компилятор выдаст ошибку, например:

main(){ String s; if (s.length > 0) // ошибка... }

При описании (определении) классов мы помещаем первой внешнюю часть, затем защищенную часть и последней – внутреннюю часть. Дело в том, что внешняя часть определяет интерфейс, использование объектов данного класса. Соответственно, при чтении программы эта часть нужна прежде всего. Защищенная часть необходима при разработке зависимых от данного класса новых классов. И внутреннюю часть требуется изучать реже всего – при разработке самого класса.

 

 





Поделиться с друзьями:


Дата добавления: 2016-11-24; Мы поможем в написании ваших работ!; просмотров: 343 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Самообман может довести до саморазрушения. © Неизвестно
==> читать все изречения...

2487 - | 2330 -


© 2015-2024 lektsii.org - Контакты - Последнее добавление

Ген: 0.007 с.