IPB
ЛогинПароль:

> Прочтите прежде чем задавать вопрос!

1. Заголовок темы должен быть информативным. В противном случае тема удаляется ...
2. Все тексты программ должны помещаться в теги [code=pas] ... [/code], либо быть опубликованы на нашем PasteBin в режиме вечного хранения.
3. Прежде чем задавать вопрос, см. "FAQ", если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Паскаля (исключение - только с согласия модератора).
5. НЕ используйте форум для личного общения, все что не относится к обсуждению темы - на PM!
6. Одна тема - один вопрос (задача)
7. Проверяйте программы перед тем, как разместить их на форуме!!!
8. Спрашивайте и отвечайте четко и по существу!!!

 
 Ответить  Открыть новую тему 
> Массив разнотипных объектов, ООП
сообщение
Сообщение #1


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Реализовать многоразовый вывод разных картинок на экран.
Я думаю это сделать с помощью ООП: сделать массив разнотипных объектов и потом просто вызывать отрисовку.
Заголовок (Показать/Скрыть)

Тут проблемы:
1. При присваивании родителю наследника некоторые поля откидываются, т. е. это не будут полноценные объекты.
2. Сreate все таки вне цикла
3. Если делать не динамическими переменными почему-то writeln('s = ',s); строку s не выводит
4. Одним местом чувствую, что с памятью что-то не то, т. к. учитывая, что идет подгонка под родителя, то почему-то памяти выделяется как под наследника.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гость






Давай по порядку:
1) зачем ты отдельно инициализируешь p1, и только потом копируешь это значение в a[1]? Сразу, на месте, сделать нельзя?

type
PTSecond1 = ^TSecond1;
TSecond1 = ... ;

// ...

a[1] := New(pTSecond1, Create(5, 7));

?
2) если у тебя есть виртуальные методы - всегда делай виртуальный деструктор.
3)
Цитата
При присваивании родителю наследника некоторые поля откидываются
Именно поэтому и делается на указателях + полиморфная процедура:
Как-то вот так (Показать/Скрыть)


Цитата
Сreate все таки вне цикла
Вне какого цикла? Оно и должно быть до цикла, цикл - по уже созданным с его помощью объектам...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Цитата
Именно поэтому и делается на указателях + полиморфная процедура
при работе с указателями памяти выделяется столько сколько нужно под целый объект, в отличии от присваивания статических объектов?
Цитата
если у тебя есть виртуальные методы - всегда делай виртуальный деструктор.
// удалять не забывай, чтоб потом когда функционал добавишь - утечек не было
хотя бы пустой написать, чтобы таблицу связей удалил?

Сообщение отредактировано: sheka -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гость






Цитата
при работе с указателями памяти выделяется столько сколько нужно под целый объект, в отличии от присваивания статических объектов?
При присваивании статических объектов Предок <- Потомок у тебя копируются только поля, существующие в предке. Все остальные - теряются, ибо места под них не было выделено (не телепат твой TFirst, чтобы знать, что у него в будущем появится потомок TSecond, а тем более, чтобы знать, какие поля он будет содержать). Зато конструктор TSecond прекрасно знает, что этот тип - потомок TFirst, и какие поля есть у потомка, и какие поля есть у него самого, сколько памяти выделить под конкретный экземпляр. Поэтому создаем объект динамически (вызовом нужного конструктора, тогда будет выделено именно столько памяти, сколько нужно для этого конкретного объекта), и передаем разыменованный указатель в полиморфную подпрограмму. А там уже забота компилятора разобраться, какой метод ты дергаешь, статический он или виртуальный, и чей именно метод будет вызван. В моем примере Draw у базового типа виртуальный - значит, вызовется Draw из того типа, который ты создавал в arr[ i ], а потом разыменовывал. Если я уберу Virtual из описания TFirst - то реально нужный мне метод уже не вызовется, отработает только пустой Draw базового класса (кстати, совершенно легальная ситуация, когда у тебя какие-то методы статические, а на каком-то этапе ты делаешь их виртуальными, и виртуальными они уже будут у всех наследников ниже по дереву. Обратное невозможно, т.е., изначально виртуальный метод не может в одном из потомков стать статическим).
Цитата
хотя бы пустой написать, чтобы таблицу связей удалил?
Хотя бы пустой напиши (для каждого типа в иерархии). Чтобы объект нормально освободил занимаемую память.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Пока получается как-то так:
Главная программа (Показать/Скрыть)

unit UBase; (Показать/Скрыть)

unit UCircle; (Показать/Скрыть)

unit ULine; (Показать/Скрыть)


Подскажите что не так, как может можно сделать красивее выбор ввода вручную или из файла?


Прикрепленные файлы
Прикрепленный файл  Viselica.rar ( 52.57 килобайт ) Кол-во скачиваний: 234
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гость






Во-первых, есть перегрузка функций (я про конструктор), во-вторых - значения по умолчанию. Совмещаем и получаем:

ULine.pas
{$mode objfpc}
unit ULine;

interface

uses
UBase;

type
TPoint = record
x, y: integer;
end;

PTLine = ^TLine;
TLine = object(TBase)
// ...
public
constructor Create(iColor:byte;
iLineType, iLineWidth: word; x1, y1, x2, y2: integer);
constructor Create(FileName: string; iColor: byte = 0);
destructor Destroy;
end;

implementation

uses
Graph;

constructor TLine.Create(iColor:byte;
iLineType, iLineWidth: word; x1, y1, x2, y2: integer);
begin
inherited Create('', iColor);
LineType := iLineType;
pb.x := x1;
pb.y := y1;
pe.x := x2;
pe.y := y2;
end;

constructor TLine.Create(FileName: string; iColor: byte);
begin
inherited Create(FileName, iColor);
end;

// ...
end.
, то же самое делаешь для UCircle.pas, и потом вызываешь:

  InitGraph(gd,gm,'');
arr[1] := new(PTLine, Create('Line1.txt'));
arr[2] := new(PTLine, Create(9,3,3,100,500,800,100));
arr[3] := new(PTCircle, Create('Circle1.txt'));
for i := 1 to n do
arr[i]^.Show;
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Вернемся к тем же баранам: Прикрепленный файл  Viselica.rar ( 5.42 килобайт ) Кол-во скачиваний: 433

В ULetterBox - массив объектов, наследников TShape. При заполнении этого массива TBar(TShape) не передаются размеры - поля, описанные в TBar. Следовательно, на экран вместо прямоугольников выводятся точки.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гость






Не понял, что именно у тебя не происходит? Ты там что-то много наворотил, можешь конкретно названия файлов и номера строк указать, в которых делается не то, что ты задумывал (и, заодно, описать что именно ты задумывал, неплохо было бы).

А вообще - опиши задачу полностью. Есть стойкое ощущение, что ты изобретаешь какой-то грандиозный велосипед. Может, это делается гораздо проще?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Задание: сделать игру "Виселица". Учитывая, что тупо выбор кейсом нажатой клавиши + выбор кейсом отрисовки ошибки есть дело одного часа + это не интересно, решил выучить ООП.
Прикрепленное изображение
Все аналогично решению в посте №2, только почему-то не работает:
В объекте ТLetterBox(модуль ULetterBox) есть поле-массив PLetter объектов типа TShape (27строка). При создании этого ТLetterBox создаются элементы этого массива (93) типа TLetterShape, который = TBar. Заполнение этого массива (42) происходит так: есть доп. переменная PSample тех же типов, что и элементы PLetter (18,154). Из файла инфо записывается сначала в нее, а потом уже копируется во все элементы массива.
Ошибка в том, что элементы массива типа TShape, а создаются с типом TBar(TShape) и таким образом не передаются размеры - поле BarDim, описанные в TBar (в UBar 19стр). Следовательно, на экран вместо прямоугольников выводятся точки. Если заменить тип элементов массива PLetter 12строка в модуле ULetterBox с TShape на TBar - то все замечательно работает.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Гость






Цитата
Ошибка в том, что элементы массива типа TShape, а создаются с типом TBar(TShape) и таким образом не передаются размеры
Ты действительно считаешь, что поведение
    PLetter^[ i ]^ := PSample^;
, где PLetter[ i ] - типа PTShape, а PSample - создан как PSample := new(PTLetterShape, Create);, то есть, фактически, ты присваиваешь TShape <- TBar, разумеется, все отсутствующие в TShape поля перенесены гарантированно не будут, по правилам присваивания предку значения-потомка - это ошибка?

Это ошибка, только чья?

А между тем, если сделать два вот таких простых движения:
1) описание типов
type
// PTLetterShape = PTBar;
PTLetterShape = ^TLetterShape; // Угу, указатель - так указатель, незачем делать двойную работу
TLetterShape = TBar;

TPLetter = array[1..maxint div sizeof(PTShape)] of PTShape;
PPLetter = ^TPLetter;

PTLetterBox = ^TLetterBox;
TLetterBox = object(TBar)
private
PSample: PTLetterShape; // <--- Вот это - движение №1
procedure PLetterCreate;
procedure PLetterDestroy;
protected
// Дальше все как было в объекте
end;

2) метод TLetterBox.LettersLoadFromFile(const FileName: string);
  for i := 1 to ColCount*(RowCount-1) do
begin
PTLetterShape(PLetter^[i])^ := PSample^; // Это - движение №2, 14 строк ниже - повтори его.
PLetter^[i]^.SetXY(LeftShift+((i-1) mod ColCount)*(PLetter^[i]^.GetWidth+ColDistance),
TopShift+((i-1) div ColCount)*(PLetter^[i]^.GetHeight+RowDistance));
readln(f,s);
PLetter^[i]^.Title.SetCaption(s);
end;
, то все заведется как положено, и будет рисоваться рамка. Просто изменение типа PSample ничего не даст. Объяснить причину сможешь?

P.S. На самом деле первое движение можно не делать, а второе сделать чуть более хитро:
    PTLetterShape(PLetter^[i])^ := PTLetterShape(PSample)^;
, это тоже должно сработать, лень проверять smile.gif
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Работает. Не даст, потому что
Цитата
фактически, ты присваиваешь TShape <- TBar, разумеется, все отсутствующие в TShape поля перенесены гарантированно не будут, по правилам присваивания предку значения-потомка
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 29.04.2024 0:51
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name