Помощь в написании студенческих работ
Антистрессовый сервис

Идентичность. 
Объектно-ориентированное программирование

РефератПомощь в написанииУзнать стоимостьмоей работы

В первой строке создается синоним: Item2 указывает на тот же объект, что и Item1. Во второй доступ к состоянию Item1 получен через этот новый синоним. К сожалению, при этом произошла утечка памяти: объект, на который первоначально указывала ссылка Item2, не именуется ни прямо, ни косвенно и его идентичность потеряна. Аргументы некоторых функций указаны с модификатором const. Он указывает, что… Читать ещё >

Идентичность. Объектно-ориентированное программирование (реферат, курсовая, диплом, контрольная)

Идентичность — это такое свойство объекта, которое отличает его от всех других объектов.

Источником ошибок в объектно-ориентированном программировании является неумение отличать имя объекта от самого объекта.

Пример.

Определим точку на плоскости.

struct Point {.

int х; // первая координата.

int у; // вторая координата.

Point (void); // конструктор по умолчанию (0,0).

Point (int xValue, int yValue); // конструктор

};

Наша абстракция Point — это пара координат (х, у). Предусмотрено два конструктора: один инициализирует точку нулевыми значениями координат, а другой — некоторыми заданными значениями.

Теперь определим точку, отображаемую на экране дисплея (DisplayPoint). Ограничимся возможностями рисовать точку и перемещать ее по экрану, а также запрашивать ее положение. Мы записываем нашу абстракцию в виде следующего объявления на C++:

class DisplayPoint {.

public:

DisplayPoint (); // конструктор по умолчанию (0,0).

DisplayPoint (const Point& location); // конструктор

~DisplayPoint (); // деструктор

void draw (); // рисует точку на экране.

void move (const Point& location); // перемещает точку.

Point location (); // возвращает координаты.

.. .

};

Аргументы некоторых функций указаны с модификатором const. Он указывает, что значение объекта, передаваемого по ссылке или указателю, в функции не изменится. Литералы, константы и аргументы, требующие преобразования типа, можно передавать как const&-аргументы и нельзя — в качестве не const &-аргументов.

Объявим экземпляры класса DisplayPoint:

DisplayPoint Item1;

DisplayPoint * Item2 = new DisplayPoint (Point (75,75));

DisplayPoint * Item3 = new DisplayPoint (Point (100,100));

DisplayPoint * Item4 = 0;

При выполнении этих операторов возникают четыре имени и три разных объекта (рис. 3.1 а). В памяти будут отведены четыре места под имена Item1, Item2, Item3, Item4. При этом Item1 будет именем объекта класса DisplayPoint, а три других — указателями. Кроме того, лишь Item2 и Item3 будут на самом деле указывать на объекты класса. У объектов, на которые указывают Item2 и Item3, к тому же нет имен, хотя на них можно ссылаться «разыменовывая» соответствующие указатели (например, *Item2). Поэтому мы можем сказать, что Item2 указывает на отдельный объект класса, на имя которого мы можем косвенно ссылаться через *Item2.

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

Рассмотрим результат выполнения следующих операторов (рис. 3.1, б):

Item1.move (Item2 -> location ());

Item4 = Item3;

Item4 -> move (Point (38, 100));

Объект Item1 и объект, на который указывает Item2, теперь относятся к одной и той же точке экрана. Указатель Item4 стал указывать на тот же объект, что и Item3. Хотя объект Item1 и объект, на который указывает Item2, имеют одинаковое состояние, они остаются разными объектами. Кроме того, мы изменили состояние объекта *Item3, использовав его новое косвенное имя Item4.

Идентичность объектов.

Рис. 3.1 Идентичность объектов

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

Структурная зависимость порождает в объектно-ориентированном программировании много проблем. Трудность распознания побочных эффектов при действиях с синонимичными объектами часто приводит к утечкам памяти, неправильному доступу к памяти и, хуже того, непрогнозируемому изменению состояния. Например, если мы уничтожим объект через указатель Item3, то значение указателя Item4 окажется бессмысленным: эта ситуация называется висячей ссылкой. Рассмотрим результат выполнения следующих действий (рис. 3.1, в):

Item2 = &Item1;

Item4 -> move (Item2 -> location ());

В первой строке создается синоним: Item2 указывает на тот же объект, что и Item1. Во второй доступ к состоянию Item1 получен через этот новый синоним. К сожалению, при этом произошла утечка памяти: объект, на который первоначально указывала ссылка Item2, не именуется ни прямо, ни косвенно и его идентичность потеряна.

В языках типа C++ такая память освобождается только тогда, когда завершается программа, создавшая объект. Такие утечки памяти могут вызвать и просто неудобство, и крупные сбои, особенно если программа должна непрерывно работать длительное время. Представьте себе утечку памяти в программе управления спутником. Перезапуск компьютера на спутнике в нескольких миллионах километров от Земли очень неудобен.

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

DisplayPoint (const DisplayPoint &); // конструктор копирования Отсутствие этого специального конструктора вызывает копирующий конструктор, действующий по умолчанию, который копирует объект поэлементно. Это разумно не всегда. Когда объект содержит ссылки или указатели на другие объекты, такая операция приводит к созданию синонимов указателей на эти объекты.

Пример. Модифицируем описание класса DisplayPoint так, чтобы каждый его экземпляр содержал указатель на точку:

class DisplayPoint {.

.. .

Point * DPoint.

.. .

};

.. .

DisplayPoint Item1;

.. .

DisplayPoint Item2(Item1);

Поэлементное копирование объекта Item1 приведет к тому, что указатели на агрегированные объекты типа Point у обоих объектов Item1 и Item2 будут указывать на один и тот же объект, содержащий местоположение отображаемой точки (рис. 3.2). Фактически, оба объекта будут ответственны за отображение одной и той же точки. Этого ли мы хотели достичь?

Присваивание — это тоже копирование и в C++ его смысл можно изменять. Например, мы могли бы добавить в определение класса DisplayPoint следующую строку:

DisplayPoint operator= (const DisplayPoint &);

Теперь мы можем записать.

Поэлементное копирование.

Рис. 3.2 Поэлементное копирование

DisplayPoint Item5;

Item5 = Item1;

Как и в случае копирующего конструктора, если оператор присваивания не переопределен явно, то по умолчанию объект копируется поэлементно.

Присваивание тесно связано с равенством. Равенство можно понимать двумя способами. Во-первых, два имени могут обозначать один и тот же объект. Во-вторых, это может быть равенство состояний у двух разных объектов. В примере, приведенном на рис. 3.1, в, для Item1 и Item2 справедлив первый вариант тождественности. А для Item2 и Item3 истинным будет второй вариант.

В С++ нет предопределенного оператора равенства, поэтому мы должны определить равенство и неравенство, объявив эти операторы при описании:

int operator == (Point&);

int operator ≠ (Point&);

Показать весь текст
Заполнить форму текущей работой