Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
251.9 Кб
Скачать

3.Полиморфизм

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

Например, методы Show у приведенных выше объектов выполняют сходные действия (рисуют), но каждый использует свой алгоритм. Все они выполняют одинаковую команду: “Нарисовать!”, но каждый по-своему. В этом смысле можно говорить о том, что методы Show объектов полиморфны. Для пояснения причин включения в методологию объектно-ориентированного программирования понятия полиморфизма рассмотрим следующую ситуацию. Пусть требуется описать некоторый сложный геометрический объект (например, чертеж детали), состоящий из не более чем NP точек, NL линий, NR прямоугольников и NC окружностей. Причем максимальное число всех элементов не более N, т.е. NP + NL + NR + NC = N.

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

Фрагмент 3.1 TYPE PointPtr = ^Point; { указатель на ТОЧКУ } LinePtr = ^Line; { указатель на ЛИНИЮ } RectanglePtr = ^Rectangle; { указатель на ПРЯМОУГОЛЬНИК } CirclePtr = ^Circle; { указатель на ОКРУЖНОСТЬ }

Так как все объекты-потомки совместимы со своими предками, то массив указателей на объекты можно описать как массив указателей на точки: VAR PIC : array [1..N] of PointPtr; Для того чтобы различать, на какой объект ссылается данный элемент массива, введем массив типов элементов: VAR TPIC : array [1..N] of byte; Добавим в текст фрагмента 1.2 фрагменты 2.2 - 2.4, а также описание указателей на объекты из фрагмента 3.1. Объединенный текст полученной программы содержит фрагмент 3.2. После выполнения данного примера на экране появится изображение

Фрагмент 3.2 USES Graph; TYPE    { = БЛОК ОПИСАНИЯ ТИПОВ = }       PointPtr = ^Point; Point = object    { объект -- точка }    x,y : integer;    Color : word;    procedure Init(xc,yc: integer; cc: word);    function GetX: integer;    function GetY: integer;    function GetColor: word;    procedure Show; end;       LinePtr = ^Line; Line = object(Point)    { объект--линия }    x1,y1 : integer;    procedure Init(xc,yc,x1c,y1c: integer;cc: word);    function GetX1: integer;    function GetY1: integer;    procedure Show; end;       RectanglePtr = ^Rectangle; Rectangle = object(Line)    { объект--прямоугольник }    procedure Show; end;       CirclePtr = ^Circle; Circle=object(Point)    { объект--оkружность }    r : integer;    procedure Init(xc,yc,rc: integer; cc: word);    function GetR: integer;    procedure Show; end;       { == БЛОК ПРОЦЕДУР И ФУНКЦИЙ =} procedure Point.Init;   { инициализация точки } Begin    x:=xc; y:=yc;    Color:=cc End; function Point.GetX;    { параметры точки} Begin    GetX:=x; End; function Point.GetY; Begin    GetY:=y; End; function Point.GetColor; Begin    GetColor:=Color; End; procedure Point.Show;   { нарисовать точку } Begin    PutPixel(x,y,Color); End; procedure Line.Init;   { инициализация линии } Begin    Point.Init(xc,yc,cc);    x1:=x1c; y1:=y1c; End; function Line.GetX1;   { параметры линии} Begin    GetX1:=x1; End; function Line.GetY1; Begin    GetY1:=y1; End; procedure Line.Show;   { нарисовать линию } Begin    SetColor(Color);    Graph.Line(x,y,x1,y1); End; procedure Rectangle.Show;   { нарисовать прямоугольник } Begin    SetColor(Color);    Graph.Rectangle(x,y,x1,y1); End; procedure Circle.Init;   { инициализация окружности } Begin    Point.Init(xc,yc,cc);    r:=rc; End; function Circle.GetR;   { параметры окружности } Begin    GetR:=r; End; procedure Circle.Show;   { нарисовать окружность } Begin    SetColor(Color);    Graph.Circle(x,y,r); End; CONST N = 100;    { число фигур } VAR i : word;       Gd,Gm,Mx,My,Xc,Yc,X1c,Y1c : integer;       M1,M2,M3 : LongInt;       P : PointPtr; L : LinePtr;       R : RectanglePtr; C : CirclePtr;       PIC : array [1..N] of PointPtr;       TPIC : array [1..N] of byte; BEGIN    { инициализируем }   Gd:=Detect;    { графический режим }   InitGraph(Gd,Gm,’ ‘);   M1:=MemAvail;   Randomize;    { включили генератор случайныхчисел }   Mx:=GetMaxX; My:=GetMaxY;    { пределы изменения координат }   for i:=1 to N do    { инициализируем фигуры }    begin {тип объекта: 0-точка; 1-линия; 2-прямоугольник; 3-окружность}     TPIC[i]:=(i-1) div 25;     Xc:=Random(Mx); Yc:=Random(My-100)+100;     X1c:=Random(Mx); Y1c:=Random(My-100)+100;     case TPIC[i] of      0:begin New(P); PIC[i]:=P; P^.Init(Xc,Yc,i) end;      1:begin New(L); PIC[i]:=L; L^.Init(Xc,Yc,X1c,Y1c,i) end;      2:begin New(R); PIC[i]:=R; R^.Init(Xc,Yc,X1c,Y1c,i) end;      3:begin New(C); PIC[i]:=C; C^.Init(Xc,Yc,Y1c div 2,i) end;     end; { case }    end; { for i }   M2:=MemAvail;   for i:=1 to N do    { рисуем фигуру }    case TPIC[i] of     0:PIC[i]^.Show;     1:LinePtr(PIC[i])^.Show;     2:RectanglePtr(PIC[i])^.Show;     3:CirclePtr(PIC[i])^.Show;    end;   for i:=1 to N do    { удаляем фигуры из памяти }    case TPIC[i] of     0:Dispose(PIC[i]);     1:Dispose(LinePtr(PIC[i]));     2:Dispose(RectanglePtr(PIC[i]));     3:Dispose(CirclePtr(PIC[i]));    end;   M3:=MemAvail;   WriteLn(‘1. Свободной памяти до инициализации :’,M1);   WriteLn(‘2. Свободной памяти после инициализации :’,M2);   WriteLn(‘3. Свободной памяти после удаления фигур:’,M3);   WriteLn(‘4. ‘,N,’ объектов занимали ’,M1-M2,’ байтов памяти’);   ReadLn;    { ожидание нажатия Enter } END.

25 точек, 25 прямых, 25 прямоугольников и 25 окружностей. В верхней части экрана будет напечатана информация о распределении памяти, которая может иметь, например, такой вид: 1. Свободной памяти до инициализации : 164984 2. Свободной памяти после инициализации : 163784 3. Свободной памяти после удаления фигур: 164984 4. 100 объектов занимали 1200 байтов памяти Объект Point имеет три поля целого типа длиной 2 байта, т.е. занимает 6 байтов памяти. Однако администратор динамической памяти ТУРБО ПАСКАЛЯ может выделять память блоками по 8 байтов. Поэтому для 25 точек будет выделено 200 байтов памяти. Соответственно для объектов Line и Rectangle будет выделено по 400 байтов (25*16 байтов) и для объекта Circle - 200 байтов. Всего 1200 байтов. Рассмотрим особенности приведенного примера. Данная программа довольно громоздка и трудно модифицируемая. Действительно, наличие операторов выбора во всех случаях, где мы работаем со сложным графическим объектом, в значительной степени усложняет алгоритм его обработки. При добавлении нового графического примитива (например, треугольника) во все операторы выбора необходимо добавить новую строку. Данное обстоятельство очень усложняет процесс модификации программы, снижает ее надежность и наглядность. Частично проблему можно решить, если описать сложный графический объект как новый объект программы. Но и в этом случае наличие операторов выбора в методах сложного объекта делают его модификацию сложным и ненадежным процессом. Необходимость иметь массив TPIC для типов объектов также усложняет программу и может служить дополнительным фактором ошибок. Анализируя приведенную в предыдущем разделе иерархию объектов, можно заметить, что все методы объектов разбиваются на три группы:     а) собственные методы данного объекта (например, методы GetX1 и GetY1 объекта ЛИНИЯ);     б) наследуемые методы предка (методы GetX, GetY и GetColor объекта ЛИНИЯ наследуются от ТОЧКИ);     в) замещаемые методы (методы Init и Show имеют свои алгоритмы у каждого объекта). Обратим особое внимание на последнюю группу методов. Замещаемые методы у объектов одной иерархии выполняют сходные действия (например, метод Show рисует), но используют для этого различные алгоритмы (т.е. они полиморфны). Причем методы типа Init должны учитывать специфику данных конкретного объекта, что выражается в различиях списков формальных параметров для заголовков методов. Методы типа Show имеют одинаковые заголовки, так как все поля данных конкретного объекта им доступны. Инициализация экземпляра сложного графического объекта выполняется только раз, а его перерисовывание в программе может выполняться многократно. Было бы заманчиво ввести в язык программирования механизм, который позволил бы сократить при работе со сложными объектами использование оператора выбора case и отказаться от массива типов элементов TPIC. Создание подобного механизма позволит решить проблему раннего и позднего связывания данных и методов их обработки. Поясним эту проблему на примерах. Пусть требуется нарисовать точку и линию. Фрагмент 3.3 содержит текст программы, выполняющей данный рисунок.

Фрагмент 3.3 VAR P : Point; L : Line; BEGIN    . . .    P.Init(100,100,White);    L.Init(100,100,200,200,Red);    P.Show;    L.Show;    . . . END.

На этапе компиляции будет установлена связь объекта с нужными методами, так что обращения P.Show и L.Show приведут к вызову разных методов. Связывание объектов с соответствующими им методами называется ранним, если оно происходит на этапе компиляции. Если связывание объектов с методами происходит на этапе выполнения, то оно называется поздним. Все рассмотренные ранее примеры программ (за исключением фрагмента 3.2) являлись примерами раннего связывания. Фрагмент 3.2 можно рассматривать в качестве примера решения проблемы позднего связывания алгоритмическим (программным) методом. Недостатки такого решения были рассмотрены выше. Однако приведенное алгоритмическое решение показало, как можно решить данную проблему: 1. позднее связывание имеет смысл применять только для замещаемых (полиморфных) методов объекта с одинаковыми заголовками (типа метода Show); 2. различные объекты иерархии можно хранить в массиве указателей на объект, являющийся предком всех объектов иерархии; 3. желательно иметь механизм, на основании которого программа могла сама бы определять, с каким объектом она работает в данный момент, и вызывать соответствующие замещаемые методы этого объекта. Решение проблемы позднего связывания в ТУРБО ПАСКАЛЕ довольно интересно и заключается в следующем.

Замещаемые (полиморфные) методы объектов, для которых необходимо реализовать механизм позднего связывания, называют ВИРТУАЛЬНЫМИ и отмечают в описании объекта специальным ключевым словом virtual. Одни и те же виртуальные методы должны иметь одинаковые заголовки у всех объектов данной иерархии. Методы, не помеченные как виртуальные, называются СТАТИЧЕСКИМИ.

Например, метод Show может быть описан следующим образом:    procedure Show; virtual; Вызов статических методов в программе ничем не отличается от вызова обычных процедур и функций и определяется на этапе компиляции программы (раннее связывание). Важным является требование об одинаковости заголовков у все однотипных виртуальных методов данной иерархии. Действительно, указатель PIC[i] в тексте фрагмента 3.2 может быть связан с любым из объектов иерархии: ТОЧКОЙ, ЛИНИЕЙ, ПРЯМОУГОЛЬНИКОМ или ОКРУЖНОСТЬЮ. Поэтому заголовок метода Show у всех данных объектов должен быть одинаков. У замещаемых невиртуальных методов данное ограничение может не выполняться, то есть список формальных параметров в заголовках методов может быть различен.

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

Т.е. нельзя, описав у ЛИНИИ метод Show виртуальным, для ПРЯМОУГОЛЬНИКА описать данный метод невиртуальным. Однако для ТОЧКИ метод Show может быть статическим. Для объектов, имеющих виртуальные методы, транслятор на этапе компиляции формирует специальную ТАБЛИЦУ ВИРТУАЛЬНЫХ МЕТОДОВ (ТВМ), содержащую адреса виртуальных методов, и помещает данную таблицу в сегмент данных программы. Очевидно, что для всех экземпляров данного объекта ТВМ является общей. В нашем случае транслятор создаст по одной ТВМ для ТОЧКИ, ОКРУЖНОСТИ, ЛИНИИ и ПРЯМОУГОЛЬНИКА. В каждый экземпляр объекта с виртуальными методами транслятор помещает дополнительное поле длиной 2 байта, предназначенное для записи смещения адреса ТВМ данного объекта в сегменте данных.

Транслятор только выделяет память под указатель на ТВМ, но не записывает туда сам адрес ТВМ.

Запись адреса в поле указателя на ТВМ может оказаться бесполезной, так как на этапе описания динамической переменной для объекта еще не известно, для какого конкретного типа объекта данная динамическая переменная будет использована. Как уже отмечалось, указатель PIC[i] в тексте фрагмента 3.2 может быть связан с любым из объектов иерархии: ТОЧКОЙ, ЛИНИЕЙ, ПРЯМОУГОЛЬНИКОМ или ОКРУЖНОСТЬЮ. После начала работы программы в поле адреса ТВМ экземпляра объекта находится случайное число. Если сейчас попробовать вызвать один из виртуальных методов объекта, то может произойти “зависание” ЭВМ (в реальном режиме работы процессора) или останов программы, так как управление будет передано по случайному адресу. Как инициализировать значение поля адреса ТВМ для данного экземпляра объекта? Для выполнения этой операции введен специальный метод constructor -- конструктор, который ничем не отличается от обычной процедуры, но перед своим выполнением заносит смещение ТВМ в поле адреса ТВМ для экземпляра данного объекта. Конструктор обычно связывают с методом инициализации значений полей объекта. Например, для объекта Point метод Init можно объявить конструктором. Для этого ключевое слово procedure необходимо заменить на constructor. Один объект может содержать несколько конструкторов с различными именами. Для объекта Point можно кроме конструктора Init описать конструктор InitNil, в котором все поля точки обнуляются:

constructor InitNil; Begin    x:=0; y:=0; Color:=0; End; Однако из одного конструктора объекта нельзя вызывать другой конструктор данного объекта. Например, вызов конструктора InitNil из конструктора Init объекта Point может привести к созданию некорректной ссылки на ТВМ. Конструктор не может быть объявлен виртуальным методом.

До вызова КОНСТРУКТОРА можно обращаться только к статическим методам объекта. Причем сами статические методы в этом случае не должны содержать вызовы любых виртуальных методов.

Операция присвоения экземпляров объектов не заменяет вызова конструктора. Следующий пример иллюстрирует выше сказанное: VAR Pa,Pb : Point; BEGIN    . . .    Pa.Init(100,100,15); { инициализировали точку А }    Pa.Show; { нарисовали точку А }    Pb:=Pa; { b = a }    Pb.Show; { вызов виртуального метода }    . . . END. Если метод Show у ТОЧКИ описан как виртуальный, данный фрагмент программы будет прерван при попытке выполнить команду Pb.Show. При этом, если включен механизм верификации (проверки) методов объектов (директива $R+ компилятора или опция Range Сhecking /Контроль границ диапазона/ интегрированной среды), то будет выдано сообщение об ошибке с номером 210 Object not initialized /Объект не инициализирован/. При отключенном механизме верификации в данном месте программа “виснет”. Для динамических экземпляров объектов их конструктор может быть вызван из процедуры New. Например, VAR P : ^Point; BEGIN    New(P,Init(100,100,15));    . . . END. Для работы с объектами синтаксис процедуры New был расширен. Во-первых, сейчас в процедуре New допускается в качестве второго параметра указывать обращение к конструктору объекта. Во-вторых, процедуру New можно вызывать как функцию. В этом случае она возвращает значение типа pointer, указывающее на динамически распределенный экземпляр объекта:      P:=New(PointPtr); { без конструктора } или      P:=New(PointPtr,Init(100,100,15)); { с конструктором }

Так как экземпляр объекта, содержащего виртуальные методы, всегда на 2 байта длиннее объекта со статическими методами, то при работе с динамической памятью данное обстоятельство должно быть учтено. Для правильного освобождения динамической памяти экземпляром объекта необходимо использовать специальный метод, который называется ДЕСТРУКТОРОМ. Если объект не имеет свои динамические поля (включая поля предков), то деструктор является пустой процедурой: destructor Destroy; virtual; Begin End; Деструктор всегда является виртуальным методом, который можно вызывать из процедуры Dispose: VAR P : PointPtr; { указатель на точку } BEGIN    P:=New(PointPtr,InitNil); { выделяем память и обнуляем поля }    . . .    Dispose(P,Destroy); { освободили память } END. Так как деструктор является виртуальным методом и не содержит формальных параметров, то рекомендуется его заголовок делать одинаковым у всех объектов в Вашей программе. Программисты фирмы Borland International рекомендует следующий заголовок для деструктора: destructor Destroy; virtual; Вызов виртуальных методов осуществляется только через ТВМ данного объекта с использованием имеющегося у экземпляра объекта поля адреса ТВМ. Фактически ТВМ можно рассматривать как дополнительную таблицу с адресами методов, которую добавляет транслятор к описанию типа данного объекта. Фрагменты 3.4 и 3.5 содержат примеры отрисовки сложного объекта традиционным способом и с использованием виртуальных методов.

Фрагмент 3.4 for i:=1 to N do { рисуем фигуру } case TPIC[i] of    0:PIC[i]^.Show;    1:LinePtr(PIC[i])^.Show;    2:RectanglePtr(PIC[i])^.Show;    3:CirclePtr(PIC[i])^.Show; end;

Фрагмент 3.5 for i:=1 to N do PIC[i]^.Show; { рисуем фигуру }

Использование механизмов позднего связывания возможно только для экземпляров объектов, описанных динамически. Действительно, описав массив PIC статически: PIC : array [1..N] of Point; можно инициализировать лишь массив ТОЧЕК. Приведенное выше описание механизма позднего связывания позволяет модифицировать иерархию геометрических объектов, включив описание виртуальных методов. Фрагмент 3.6 содержит описание библиотеки измененных объектов, оформленных в виде отдельного модуля Graph_A.

Фрагмент 3.6 UNIT Graph_A;    { ** БИБЛИОТЕКА ГРАФ. ОБЪЕКТОВ ** } INTERFACE USES Graph; CONST NMax=100; { max число объектов } TYPE { БЛОК ОПИСАНИЯ ТИПОВ }      PointPtr = ^Point; Point = object { объект--точка }    x,y : integer;    Color : word;    constructor Init(xc,yc: integer; cc: word);    destructor Destroy; virtual;    function GetX: integer;    function GetY: integer;    function GetColor: word;    procedure Show; virtual; end;      LinePtr = ^Line; Line = object(Point) { объект--линия }    x1,y1 : integer;    constructor Init(xc,yc,x1c,y1c: integer; cc: word);    function GetX1: integer;    function GetY1: integer;    procedure Show; virtual; end;      RectanglePtr = ^Rectangle; Rectangle = object(Line)

{ объект--прямоугольник }    procedure Show; virtual; end;      CirclePtr = ^Circle; Circle=object(Point){ объект--Окружность }    r : integer;    constructor Init(xc,yc,rc: integer; cc: word);    function GetR: integer;    procedure Show; virtual; end; { массив указателей на эл-ты изображения } PType = array [1..NMax] of PointPtr; PPtr = ^PType; IMPLEMENTATION constructor Point.Init; { --- инициализация точки --- } Begin    x:=xc; y:=yc;    Color:=cc End; destructor Point.Destroy; Begin End; function Point.GetX; { параметры точки } Begin    GetX:=x;    End; function Point.GetY; Begin    GetY:=y; End; function Point.GetColor; Begin    GetColor:=Color; End; procedure Point.Show; { нарисовать точку } Begin    PutPixel(x,y,Color); End; constructor Line.Init; { --- инициализация линии --- } Begin    Point.Init(xc,yc,cc);    x1:=x1c; y1:=y1c; End; function Line.GetX1; { параметры линии } Begin    GetX1:=x1; End; function Line.GetY1; Begin    GetY1:=y1; End; procedure Line.Show; { нарисовать } Begin    SetColor(Color);    Graph.Line(x,y,x1,y1); End; procedure Rectangle.Show; { --- нарисовать прямоугольник --- } Begin    SetColor(Color);    Graph.Rectangle(x,y,x1,y1); End; constructor Circle.Init; { --- инициализация окружности --- } Begin    Point.Init(xc,yc,cc);    r:=rc; End;

function Circle.GetR; { параметры } Begin    GetR:=r; End; procedure Circle.Show; { нарисовать } Begin    SetColor(Color);    Graph.Circle(x,y,r); End; END. { # КОНЕЦ МОДУЛЯ Graph_A # }

Фрагмент 3.7 содержит версию программы, описанной во фрагменте 3.2, но с использованием модуля Graph_A. После выполнения программы фрагмента 3.7 на экране появится изображение 25 точек, 25 прямых, 25 прямоугольников и 25 окружностей. В верхней части экрана будет напечатана информация о распределении памяти, которая может иметь, например, такой вид: 1. Свободной памяти до инициализации:165208 2. Свободной памяти после инициализации :163808 3. Свободной памяти после удаления фигур:165208 4. 100 объектов занимали 1400 байтов памяти Экземпляр объекта Point занимает 8 байтов, Line и Rectangle - по 12 байтов и Circle - 10 байтов. С учетом особенностей работы администратора динамической памяти для 25 объектов каждого вида выделяется: 200+400+400+400 = 1400 байтов.

Фрагмент 3.7 USES Graph, Graph_A; CONST N = 100; { число фигур } VAR i,TPIC : word;      Gd,Gm,Mx,My,Xc,Yc,X1c,Y1c : integer;      M1,M2,M3 : LongInt;      PIC : array [1..N] of PointPtr; BEGIN { инициализируем }    Gd:=Detect; { графический режим }    InitGraph(Gd,Gm,' ');    M1:=MemAvail;    Randomize; { вкл. генератор случайных чисел }    Mx:=GetMaxX; My:=GetMaxY; { пределы координат }    for i:=1 to N do { инициализируем фигуры }     begin {тип объекта: 0-точка; 1-линия; 2-прямоугольник; 3-окружность}      TPIC:=(i-1) div 25;      Xc:=Random(Mx); Yc:=Random(My-100)+100;      X1c:=Random(Mx); Y1c:=Random(My-100)+100;      case TPIC of      0:PIC[i]:=New(PointPtr,Init(Xc,Yc,i));      1:PIC[i]:=New(LinePtr,Init(Xc,Yc,X1c,Y1c,i));      2:PIC[i]:=New(RectanglePtr,Init(Xc,Yc,X1c,Y1c,i));      3:PIC[i]:=New(CirclePtr,Init(Xc,Yc,Y1c div 2,i));      end;     end;    M2:=MemAvail;    for i:=1 to N do PIC[i]^.Show; { рисуем фигуру }    for i:=1 to N do Dispose(PIC[i],Destroy); { удаляем фигуры из памяти }    M3:=MemAvail;    WriteLn('1. Свободной памяти до инициализации :',M1);    WriteLn('2. Свободной памяти после инициализации :',M2);    WriteLn('3. Свободной памяти после удаления фигур:',M3);    WriteLn('4. ',N,' объектов занимали ‘,M1-M2,' байтов памяти');    ReadLn; { ожидание нажатия Enter } END.

Контрольные вопросы

1. Что такое полиморфизм? 2. Что означает раннее и позднее связывание полей данных и методов объекта? 3. Какие методы называют виртуальными? Статическими? 4. Перечислите требования, накладываемые на виртуальные методы. 5. Можно ли позднее связывание реализовать алгоритмическим путем? Перечислите достоинства и недостатки такого подхода. 6. Можно ли позднее связывание реализовать для статических экземпляров объектов? Почему? 7. Что такое ТВМ? Где она находится? Ее назначение? 8. Что такое конструктор? Какие функции он выполняет? 9. Может ли конструктор быть объявлен виртуальным методом? 10. Как осуществляется вызов виртуального метода? 11. Почему вызов виртуального метода до вызова конструктора невозможен? 12. Что такое деструктор? Его назначение? 13. Может ли деструктор быть виртуальным методом? А статическим? 14. С чем связана необходимость иметь деструктор? Для каких объектов деструктор не нужен? А конструктор?

Лабораторная работа №3

1. Набрать текст программы фрагмента 3.2. Выполнить данный пример и посмотреть результат. 2. Набрать текст программ фрагментов 3.6 и 3.7. Выполнить данный пример и посмотреть результат. 3. Разработать объект ДИАЛОГОВОЕ ОКНО как потомок объекта ОКНО. В качестве диалоговых полей ввода данных использовать иерархию объектов ПОЛЯ ВВОДА. 4. Разработать объект ОКНО ПОМОЩИ, являющийся потомком объекта ОКНО. 5. Матрицу вещественных чисел можно представить как объект. Матрица может располагаться в оперативной памяти и на диске. Предложите иерархию матриц, использующие разные способы хранения. 6. С помощью ООП разработайте возможную реализацию некоторого компьютерного мира. Жители такого мира могут быть неподвижными и подвижными, быстрыми и медленными. Они могут нападать на другие объекты данного мира и уметь защищаться от нападения. Придумать правила для размножения и гибели объектов. 7. Разработайте с помощью ООП возможный вариант графического редактора. Предложите иерархию объектов, которая могла бы быть использована для подобного редактора.