наследование объектов с дин. массивом - как?

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

наследование объектов с дин. массивом - как?

Сообщение AlexP » 24.03.2008 06:13:24

Столкнулся с тем, что если обьект является наследником другого обьекта с динамическим массивом, то из обьекта-наследника невозможно обратиться к этому массиву.

Вот код -

Код: Выделить всё
type a=object
x:array of integer;
end;

type b=object(a)
procedure ini;
end;

procedure b.ini;
begin
setLength(x,10);
end;

...

var k:b;
begin
k.ini;
end;


и при выполнении строки k.ini возникает exception: External: SIGSEGV
В чем тут ошибка и как правильно обращаться с такими обьектами?
AlexP
новенький
 
Сообщения: 20
Зарегистрирован: 11.05.2007 19:04:01

Сообщение Sergei I. Gorelkin » 24.03.2008 09:04:49

object, если мне память не изменяет, автоматически не инициализируется, это надо делать вручную. Можно попробовать что-то типа Pointer(x) := nil перед первым использованием SetLength.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение alexs » 24.03.2008 09:33:39

А где вызов конструктора?
или переименовую процедуру в констурктор и делай там дополнительно inherited Init; первой строкой или перепиши вызывающий код так:

var k:b;
begin
k.Init;
k.ini;
end;


Суть ошибки - ты пытаешся обратиться к методу объекта без вызова контсруктора объекта. В принципе для объектов это допустимо - но нет первичной инициализаиции переменных.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Сообщение Vadim » 24.03.2008 11:44:52

Не путайте объекты с классами. Классы могут быть только динамическими, т.е. под них надо память выделять, а вот объекты могут существовать как статическая переменная, тогда память им выделяет компилятор. Вот примерчик:
Uses Objects;

type
a=object
x:array of integer;
end;

type
b=object(a)
procedure ini;
end;

procedure b.ini;
begin
setLength(x,10);
end;

var
k:b;
i: integer;
begin
k.ini;
For i:=0 To 9 Do
k.x[i]:=i;
For i:=0 To 9 Do
WriteLn(k.x[i]);
end.

И вот его работа:
0
1
2
3
4
5
6
7
8
9

Как видите проблем, если только товарищ AlexP не забыл упомянуть о чём нибудь существенном, быть никаких не должно, тем более таких глобальных, как описано вначале.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение AlexP » 24.03.2008 13:03:34

О, спасибо! Про конструктор я как-то забыл, с ним заработало 8)
AlexP
новенький
 
Сообщения: 20
Зарегистрирован: 11.05.2007 19:04:01

Сообщение AlexP » 24.03.2008 14:07:29

Vadim писал(а):Как видите проблем, если только товарищ AlexP не забыл упомянуть о чём нибудь существенном, быть никаких не должно, тем более таких глобальных, как описано вначале.


Наверное забыл упомянуть о том, что работаю в Лазарусе.
В FPC 2.0.4 ваш код заработал, и в лазарусе (0.9.24 FPC 2.2.0) он тоже работает, но только тогда, когда b объявлена как глобальная переменная. А когда она обьявлена как локальная, то в Лазарусе возникает ошибка, а в FPC - нет. И когда в Лазарусе в в обьекте вместо динамического массива обычный, то ошибки тоже не возникает.

Собстно вот код, при котором возникает ошибка -

Код: Выделить всё
...

type
a=object
x:array of integer;
end;

type
b=object(a)
procedure ini;
end;

var Form1: TForm1;

implementation { TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
k:b;
begin
k.ini;
For i:=0 To 9 Do
k.x[i]:=i;
For i:=0 To 9 Do
memo1.lines.add(inttostr(k.x[i]));
end;

procedure b.ini;
begin
setLength(x,10);
end;
...


на форме одно мемо, одна кнопка, больше ничего нет.
AlexP
новенький
 
Сообщения: 20
Зарегистрирован: 11.05.2007 19:04:01

Сообщение Иван Шихалев » 24.03.2008 14:21:17

Тогда ситуация понятна... Глобальные переменные в FPC всегда инициализируются нулями, тогда как локальные — содержат мусор из стека. Точнее, будь объявлен динамический массив просто, был бы вставлен код его инициализации, но поскольку он завернут в object, то компилятор не считает нужным это делать (на самом деле, такой код был бы неявно вставлен в конструктор). Выход — все-таки использовать конструктор.
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Сообщение alexs » 24.03.2008 16:26:58

Vadim
Я именно это и учитывал.
Объекты от классов эти и отличаются - объкты могут быть статическими и все переменные их будут зарезервированны при объявлении переменной - фактически это тип record.

А вот класс - это только динамическая структура. И без вызова конструктора класса доступ к полям класса сразу приведёт к ошибке доступа к памяти.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Сообщение Vadim » 24.03.2008 17:07:15

Ну тут ошибка доступа к памяти как раз у статической "структуры". :) С одной стороны переменная (указатель на массив) уже должна существовать, чтобы выделить ей память, а с другой стороны её нету, т.к. объект-потомок прётся куда-то не в ту степь.
Всё таки, наверное, лучше пользоваться классами, чем объектами, которые достались в наследство от ТР. :)
Хотя, с другой стороны, если я, например, работаю на протяжении всей работы программы только с одним объектом и не предполагается использовать другие, то объекты предпочтительнее. Когда-то использовал таблицы типа DBF для хранения оперативной информации при работе программы (ещё в ТР). Создал для этого специальный объект, который загружает DBF, заносит данные или ищет их по шаблону. Работало очень быстро и не надо было заморачиваться на создание-удаление, хотя и тут без INIT никак не обойтись, т.к. требовались некоторые значения по умолчанию.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение AlexP » 24.03.2008 17:40:06

А я пишу библиотеку для работы с линейной алгеброй, там нужны динамические массивы для описания векторов-матриц. А обьекты нужны потому что можно им операторы переопределять, что для линейной алгебры очень удобно.

Тут кстати столкнулся с одной сложностью - как известно, результат умножения векторов может быть число, вектор или матрица.

Пишу так -

operator *(const a,b:tvectora)r:tvectora;
operator *(const a,b:tvectora)r:double;

но, естественно, получаю на обьявление второго оператора ошибку

Error: function header doesn't match the forward declaration "operator *(const tvectora,const tvectora):tvectora"

пробую -

operator *(const a,b:tvectora)r:tvectora; overload;
operator *(const a,b:tvectora)r:double; overload;

получаю то же самое. Пока выкрутился так -

operator *(const a,b:tvectora)r:tvectora;
operator **(const a,b:tvectora)r:double;

Для результата-матрицы пришлось так написать -

operator /(const a,b:tvectora)r:tmatrixa;

Это не очень-то красиво, может есть какой другой путь?
AlexP
новенький
 
Сообщения: 20
Зарегистрирован: 11.05.2007 19:04:01

Сообщение Sergei I. Gorelkin » 24.03.2008 18:11:05

AlexP писал(а):Это не очень-то красиво, может есть какой другой путь?


Есть - не использовать операторы.

Количество проблем, которые они создают, не идет ни в какое сравнение с сэкономленными на их использовании нажатиями кнопок...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение alexs » 24.03.2008 19:01:20

Vadim писал(а):Ну тут ошибка доступа к памяти как раз у статической "структуры"

Был не вызван контсруктор, соответсвенно указатель на динамический массив не был проинициализирован. И, как я понимаю, при вызове setLength(x,10); так как указатель не x<>nil то процедура пытается использовать старые данные - а их нет.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Сообщение Vadim » 24.03.2008 19:21:06

alexs
...соответсвенно указатель на динамический массив не был проинициализирован...

А по идее бы должен был, т.к. переменная объекта - статическая, а не динамическая. И мы это видим (инициализацию компилятором), если переменную сделать глобальной. При глобальном объявлении конструктор тоже не был вызван, тем не менее поле объекта оказалось на своём месте.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение trifon » 24.03.2008 19:37:39

Предлагаю вместо динамического массива использовать указатель,
выделять и освобождать память при помощи getmem и freemem, будет проще и код быстрей.
trifon
постоялец
 
Сообщения: 135
Зарегистрирован: 24.12.2006 12:08:35

Сообщение Sergei I. Gorelkin » 24.03.2008 19:44:54

Если я не ошибаюсь, секция с глобальными переменными обнуляется при запуске программы операционной системой, или, в случае DOS - runtime библиотекой. Компилятор же в этом процессе не участвует.

Поведение объектов совместимо с Turbo Pascal, в котором никакой "автоматики" (длинных строк, дин. массивов, интерфейсов) еще не было.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru