Опорный конспект Форма ф со пгу 18. 2/05 Министерство образования и науки Республики Казахстан

Вид материалаКонспект

Содержание


4.4 Создание собственных методов
ООП называются методами. Подобно тому, как структуры в Си
Конструкторы и деструкторы
4.5 Порождение объектов от порождающих классов
Пояснения к примеру
Подобный материал:
1   ...   5   6   7   8   9   10   11   12   ...   15

4.4 Создание собственных методов



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

Наши объектно-ориентированные объекты - это объединение функций и данных (включая простые переменные и структуры) в виде независимой конструкции.

Объекты подобны миниатюрным программам. Они содержат и данные, и функции, которые в терминологии ООП называются методами.

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

Конструкторы и деструкторы


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

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

Имя деструктора также совпадает с именем класса, но перед ним записывается символ тильда (~). Для деструктора также не указывается возвращаемый тип.

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

Конструктор для данного класса может быть и не один, как в приведенном ниже примере.

4.5 Порождение объектов от порождающих классов



Пример определения класса средствами C

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

В приведенном ниже примере такому классу присвоено имя DefsWord. Каждый объект (экземпляр) этого класса может содержать само слово, которому дается определение и до 5 его различных значений. Для того, чтобы избежать лишнего расхода памяти, в качестве полей используются указатели:
  1. указатель на само слово
  2. массив указателей на его возможные значения

Естественно, прежде чем присвоить значение одному из полей данных такого типа, необходимо:
  1. Выделить в динамически распределяемой области памяти (хипе) необходимое для хранения слова или его значения место.
  2. Присвоить значение соответствующему указателю на выделенную область памяти.

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

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

#include

#include

#include

const int Maxmeans = 5;

//описание класса Defs:

class DefsWord

{ //до ключевого слова public все определения считаются

//private, т.е в данном примере private можно пропустить

private:

char *word; // Слово, которому дается определение

char *meanings[Maxmeans]; // Различные значения этого слова

int nmeanings; // количество различных значений


public: //методы, или функции-члены

void put_word(char *); //определить слово

//вернуть слово – определение функции в одну строку!

char *get_word(char *s) {return strcpy(s,word);};

void add_meaning(char *); //добавить новое значение слову

char *get_meaning(int, char *); //вернуть одно из значений слова

};

//Описания функций - членов:

//Все описания содержат оператор разрешения области действия ::

//который указывает что функция относится к данному классу

//(scope access (or resolution) operator)

void DefsWord ::put_word(char *s)

{

word = new char[strlen(s)+1]; //Оператор new выделяет место в хипе

strcpy(word,s); //помещаем переданное значение в поле объекта

nmeanings = 0; //инициализируем поле объекта

}


void DefsWord ::add_meaning(char *s)

{ //добавляем новое значение к слову

if (nmeanings < Maxmeans)

{

meanings[nmeanings] = new char[strlen(s)+1];

strcpy(meanings[nmeanings++],s);

}

}


char * DefsWord ::get_meaning(int level, char *s)

{ //возвращаем одно из значений слова

if (0 <= level && level < nmeanings)

return strcpy(s,meanings[level]);

else

return 0;

}

//Начало программы

main()

{

DefsWord d;

//Определяем новый объект(экземпляр класса) типа DefsWord

//в области памяти программы

char s[81];

clrscr();

// Присваиваем значения слову "Class"

d.put_word("Class");

d.add_meaning("Группа учащихся");

d.add_meaning("Аудитория");

d.add_meaning("Разряд, категория");

d.add_meaning("Понятие ООП");

// Печатаем все значения слова:

cout << d.get_word(s) << ":\n\n";

for (int i = 0; d.get_meaning(i,s) != 0; ++i)

cout << (i+1) << ": " << s << "\n";

getch();

return 0;

}

Пояснения к примеру


Оператор new пытается создать в хипе место для указанного объекта или переменной. В случае успеха он возвращает соответствующий указатель. К оператору new существует обратный ему оператор delete, который возвращает выделенную область памяти в хип. Приведем пример использования обеих операторов:

name *nameptr; // Здесь name – это имя какого-либо типа

...

if (!(nameptr = new name)) {

errmsg("Не хватает памяти");

exit (1);

}

// Далее можем использовать возвращенный указатель *nameptr

// для работы с объектом

...

delete nameptr; //освобождаем память и разрушаем ссылку на объект


Операция sizeof определяет размер в байтах своего операнда – переменной, типа, объекта и возвращает беззнаковое значение.

Операция разрешения области действия (::) обозначается двумя двоеточиями без пробела. Имеется два формы такой операции:
  1. унарная вида ::переменная
  2. бинарная вида класс :: элемент_класса

Бинарная форма позволяет сослаться на данные-элемент или функцию-элемент класса даже если имеются одноименные переменные или функции, определенные вне класса или в нескольких классах. Она используется также при описании функции-элемента вне класса.

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

Доступ к элементам структур и классов может осуществляться двумя операциями: операцией точки (.) или операцией стрелки (->). Если доступ осуществляется через объект, то используется операция точка. Например, если объект с именем A имеет свойство Prop и метод F(), то доступ к ним дается выражениями:

A.Prop

A.F()

Если доступ осуществляется через указатель на объект, то используется операция стрелка (->). Например:

Label1->Caption

Label1->Hide()

Можно и в этом случае использовать операцию точка, но тогда надо сначала разименовать указатель, например:

(*Label1).Caption

Изменим функцию main в приведенной выше программе, и определим экземпляр класса как указатель:

…………………………

//Начало программы

main()

{

//Определяем новый объект типа DefsWord

//динамически размещая его в памяти:

DefsWord *d = new DefsWord;

char s[81];

clrscr();

// Присваиваем значения слову "Class"

d->put_word("Class");

d->add_meaning("Группа учащихся");

d->add_meaning("Аудитория");

d->add_meaning("Разряд, категория");

d->add_meaning("Понятие ООП");

// Печатаем все значения слова:

cout << d->get_word(s) << ":\n\n";

for (int i = 0; d->get_meaning(i,s) != 0; ++i)

cout << (i+1) << ": " << s << "\n";

getch();

return 0;

}