ООП и др.
1. Паскале есть зарезервированные слова Record, Class (на счет этого не уверен), Object, подскажите в чем различие (какое когда нужно использовать)
2. Нашел на сайте http://rrc.dgu.ru/res/www.isu.ru/~slava/teach/delphi/Curses/Problems/4.htm следующее:
Особенности языка Object Pascal в Delphi
Структура файла проекта и модулей
Существенные отличия языка
- классы
- class и object. Ссылки и значения. TObject.
- Динамические и статические экземпляры объектов.
{ Старая объектная модель }
type
PMyObject = ^TMyObject;
TMyObject = object (TObject)
MyField : PMyType;
constructor Init;
end;
var
MyObject : PMyObject;
begin
MyObject:=New(PMyObject,Init);
MyObject^.MyField:= ...
end;
{ Новая объектная модель }
type
TMyObject = class(TObject)
MyField : TMyType;
end;
var
MyObject : TMyObject;
begin
MyObject:=TMyObject.Create;
MyObject.MyField:= ...
end;
Т.е. в дельфи не используется Object, а надо писать Class, и при этом сразу же все классы, переменные, процедуры и функции обозначаются как динамические?
И еще подскажите, что за класс TObject - описания его не вижу, он изначально существует?
Особенности языка Object Pascal в Delphi
"TObject is the ultimate ancestor of all objects and components."
Поищи в хелпе про TObject там есть.
Насколько я понимаю отличия record от class - то оно аналогично отличию "структуры" от "класса" в С++.
Обсуждалось.
Все отлично, вчитался, узнал много нового, но там ни слова не сказано когда нужно применять class, когда object, а когда record.
А еще не понятно, про динамическую память (конец первого сообщения)
но там ни слова не сказано когда нужно применять class, когда object, а когда record.
Зависит от задачи.
Вопрос некорректен.
Все отлично, вчитался, узнал много нового, но там ни слова не сказано когда нужно применять class, когда object, а когда record.
использование object в Delphi - это архаизм. они не используются и оставлены в языке для обратной совместимости. Для реализации ООП в Delphi предусмотрены class'ы.
А record можно юзать во всех остальных случаях, например для хранения массива какой-нибудь структурированной инфы, когда создавать экземпляры class'ов муторно и неудобно.
{ Старая объектная модель }
type
PMyObject = ^TMyObject;
TMyObject = object (TObject)
MyField : PMyType;
constructor Init;
end;
var
MyObject : PMyObject;
begin
MyObject:=New(PMyObject,Init);
MyObject^.MyField:= ...
end;
{ Новая объектная модель }
type
TMyObject = class(TObject)
MyField : TMyType;
end;
var
MyObject : TMyObject;
begin
MyObject:=TMyObject.Create;
MyObject.MyField:= ...
end;
Остается непонятным вид новой объектной модели в сравнении со старой (этот код я взял из какого-то учебника указанного в ссылке). Как следует из примера, в старой объектной модели требовалось ручками прописать, что тип PMyObject является динамическим. В новой же тип TMyObject является динамическим изначально (потому что является потомком типа TObject) для него не требуется применять операцию выделения памяти и всё с этим связанное. В таком случае класс TObject является динамическим.Я правильно понял(исходя только из листинга)?
Остается непонятным вид новой объектной модели в сравнении со старой (этот код я взял из какого-то учебника указанного в ссылке). Как следует из примера, в старой объектной модели требовалось ручками прописать, что тип PMyObject является динамическим. В новой же тип TMyObject является динамическим изначально (потому что является потомком типа TObject) для него не требуется применять операцию выделения памяти и всё с этим связанное. В таком случае класс TObject является динамическим.Я правильно понял(исходя только из листинга)?
Что это за понятие - динамический тип? Все гораздо проще: в "старом" паскале объектная модель является аналогом C++ модели, т.е. все типы object являются аналогом class в C++. Объявление переменной например MyObject: TMyObject автоматически создает объект MyObject и под него выделяется память (если объявление находиться в процедуре функции, то память выделяется в стеке, если переменная объявляется в в модуле, то память - глобальная). Чтобы создать объект динамически, то необходимо объявлять тип указатель на объект (PMyObject = ^TMyObject), поскольку при динамическом выделении блока памяти, необходим указатель, который указывает на этот блок.
PMyObject = ^TMyObject;
TMyObject = object
private
X: Integer;
public
constructor Init;
procedure SetX(Value: Integer);
end;
constructor TMyObject.Init;
begin
X:=0;
end;
procedure TMyObject.SetX(Value: Integer);
begin
X:=Value;
end;
procedure ManageObjects;
var MyObject: TMyObject; // Создан объект в стеке
pMyObj: PMyObject;
begin
MyObject.Init; // X:=0;
MyObject.SetX(100); // Нормальная работа с объектом
// pMyObj^.Init - ошибка, указатель ни на что не ссылается
pMyObj:=New(PMyObject, Init); // Создаем объект в динамической памяти и
// вызываем его метод Init
pMyObj^.SetX(100); // Теперь все нормально
Dispose(pMyObj); // Освобождаем память
end;
Так было в "старом" паскале.
В Object Pascal совершенно другой подход к созданию объектов. Объявление переменной некоего класса, где бы она не была объявлена, не приводит к созданию объекта как такового. Будет объявлена только ссылка на него (считай, указатель), ни на что не ссылающаяся.
TMyObject = class
private
X: Integer;
public
constructor Create;
procedure SetX(Value: Integer);
end;
constructor TMyObject.Create;
begin
inherited; // Вызов конструктора базового класса обязателен
X:=0;
end;
procedure TMyObject.SetX(Value: Integer);
begin
X:=Value;
end;
procedure ManageObjects;
var MyObject: TMyObject; // Объявлена ссылка на объект
begin
// MyObject.SetX(100); // Здесь возникнет исключение Access violation (попытка обращения к несуществующему адресу памяти)
MyObject:=TMyObject.Create; // Создаем объект в динамической памяти
MyObject.SetX(100); // Теперь все нормально
MyObject.Free; // Освобождаем память
end;
Еще остается добавить, что все классы в Object Pascal наследуются от класса TObject, задача которого - выделение памяти под объект и инициализация всех полей класса нулевыми значениями.
А вообще стоит купить какую нибуть хорошую книгу (к примеру М. Канту) и прочитать :) Еще рекомендую почитать статьи в разделе "Лицей" на Королевстве Дельфи. Успехов!
Что это за понятие - динамический тип? Все гораздо проще: в "старом" паскале объектная модель является аналогом C++ модели, т.е. все типы object являются аналогом class в C++. Объявление переменной например MyObject: TMyObject автоматически создает объект MyObject и под него выделяется память (если объявление находиться в процедуре функции, то память выделяется в стеке, если переменная объявляется в в модуле, то память - глобальная). Чтобы создать объект динамически, то необходимо объявлять тип указатель на объект (PMyObject = ^TMyObject), поскольку при динамическом выделении блока памяти, необходим указатель, который указывает на этот блок.
Так было в "старом" паскале.
В Object Pascal совершенно другой подход к созданию объектов. Объявление переменной некоего класса, где бы она не была объявлена, не приводит к созданию объекта как такового. Будет объявлена только ссылка на него (считай, указатель), ни на что не ссылающаяся.
Вот это и есть динамический объект. Его можно создавать в любом месте программы. Можно несколько раз.
И я не понял почему ты именно старую модель сравниваешь с С++??? Class - это как раз динамический тип, а в старой модели - статический. Новая модель на много больше похожа на сишную.
И я не понял почему ты именно старую модель сравниваешь с С++??? Class - это как раз динамический тип, а в старой модели - статический. Новая модель на много больше похожа на сишную.
Ты в этом точно уверен? :D :D
Значит ты не разобрался с семантикой ООП в С++ :P
В С++ при объявлении экземпляра некоторого класса вызов конструктора происходит автоматически. А чтоб создавать объект тогда, когда мы хотим, нам нужно объявлят указатель на объект в явном виде, чего не требуется делать, когда мы используем "новую" парадигму ООП в Делфи.
А то, что ты называешь "похожестью" на модель ООП в С++, то это - просто проявление хорошей реализации ООП в Делфи. Кроме того Борланд ведёт параллельно С++ Билдер и Делфи, которые используют единую библиотеку классов VCL.
Описать дин. массив можно так:
var DMas:array of char;
После чего в программе надо задать его длину:
SetLength(DMas,16);
До этого момента я все правильно написал!
Далее. У меня есть функция, в из которой по ссылке передается динамический массив:
Например,
function FUN(var M:array of char):word;
var i:integer;
begin
....
for i:=1 to 15 do
M:='{символ}';
result:=i;
end;
{все написано для примера}
После этого мне надо из программы вызвать эту функцию и получить значения массива М из нее:
var DMas:array of char;
a:integer;
begin
SetLength(DMAS,16);
a:=FUN(DMAS);
end.
Но вместо того, чтобы выполниться, он говорит о несовпадении типов Array и DynamicArray
В чем байда?
Хорошо, тогда у меня есть еще один вопрос по поводу динамических массивов.
Описать дин. массив можно так:
var DMas:array of char;
После чего в программе надо задать его длину:
SetLength(DMas,16);
До этого момента я все правильно написал!
Далее. У меня есть функция, в из которой по ссылке передается динамический массив:
Например,
function FUN(var M:array of char):word;
var i:integer;
begin
....
for i:=1 to 15 do
M:='{символ}';
result:=i;
end;
{все написано для примера}
После этого мне надо из программы вызвать эту функцию и получить значения массива М из нее:
var DMas:array of char;
a:integer;
begin
SetLength(DMAS,16);
a:=FUN(DMAS);
end.
Но вместо того, чтобы выполниться, он говорит о несовпадении типов Array и DynamicArray
В чем байда?
Типичная ошибка в коде:
Функции и процедуры не позволяют описывать массивы в области задания входных и выходных параметров.
Поэтому тебе надо было объявить тип и уже рабоатать через него:
Mas_CHAR=array of char;
...
function FUN(var M:Mas_CHAR):word;
var i:integer;
begin
....
for i:=1 to 15 do
M:='{символ}';
result:=i;
end;
var DMas:Mas_CHAR;
a:integer;
begin
SetLength(DMAS,16);
a:=FUN(DMAS);
end.
Типичная ошибка в коде:
Функции и процедуры не позволяют описывать массивы в области задания входных и выходных параметров.
Поэтому тебе надо было объявить тип и уже рабоатать через него:
Ни фига - в паскале нельзя, а дельфи можно. Можно объявиться массив как обычно в этих самых областях
function FUN(var Mas:array of char):word;
и сама функция работает(проверял через степинг).
Но при ее вызове в программе возникает ошибка несовместимости типов статических и динамических.
Т.е. если эту самую функцию вызвать в программе,
то возвращаемый массив должен быть описан как статический,
т.е:
a:integer;
begin
a:=FUN(DMAS);
end.
Так все работает, но теряется смысл использования динамических массивов.
Так все работает, но теряется смысл использования динамических массивов.
Ни фига не теряется. Надо внимательней курить доку.
Конструкция array of без указания размерности в описании типа описывает динамический массив, а в заголовке процедуры, т. н. открытый массив. Его еще можно назвать встроенным (inline) динамическим массивом. С точки зрения Object Pascal это другая синтаксическая конструкция, выступающая в качестве альтернативы объявлению переменного числа параметров в Си. Так, например, объявлена функция Format.
Передача параметров в процедуру должна отвечать совместимости по присваиванию. Если исключить неявное преобразование простых типов, совместимость достигается совместимостью по описанию. Поэтому и надо описывать отдельный тип.
Type
Form1 = class(TFORM)
.........
end;
////1////
TTPS = class
.........
function FUN(var Mas:array of char):word;
end;
end;
implementation
////2///
begin
......
end.
Вопрос заключается в том, где этот самый тип надо описывать?Если описать его перед TTPS, то возникает какая-то ошибка, если в разделе implementation, то снова какая-то ошибка (честно говоря не помню какая - вчера вечером этим занимался и еще дома не был)
Ни фига не теряется. Надо внимательней курить доку.
Конструкция array of без указания размерности в описании типа описывает динамический массив, а в заголовке процедуры, т. н. открытый массив. Его еще можно назвать встроенным (inline) динамическим массивом. С точки зрения Object Pascal это другая синтаксическая конструкция, выступающая в качестве альтернативы объявлению переменного числа параметров в Си. Так, например, объявлена функция Format.
Передача параметров в процедуру должна отвечать совместимости по присваиванию. Если исключить неявное преобразование простых типов, совместимость достигается совместимостью по описанию. Поэтому и надо описывать отдельный тип.
Т.е. ты хочешь сказать, что массив описанный в программе
var DMas:array[1..16] of char;
тоже является динамическим. Но если так, то как его уничтожить после того, как он стал не нужен?
Т.е. ты хочешь сказать, что массив описанный в программе
var DMas:array[1..16] of char;
Ключевое слово в моей фразе - без указания размерности.
тоже является динамическим. Но если так, то как его уничтожить после того, как он стал не нужен?
RTFM, RTFM и еще раз RTFM!
Да я как бы и не прочь описать как отдельный тип...
Вопрос заключается в том, где этот самый тип надо описывать?Если описать его перед TTPS, то возникает какая-то ошибка, если в разделе implementation, то снова какая-то ошибка (честно говоря не помню какая - вчера вечером этим занимался и еще дома не был)
рабочий код...
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyMas = Array of Char;
TTPS = class
function FUN(Mas: TMyMas): Word;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TTPS }
function TTPS.FUN(Mas: TMyMas): Word;
var
I: Integer;
begin
I := 0;
while I < Length(Mas) do begin
Mas := '1';
Inc(I);
end;
Result := I;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
TPS: TTPS;
Mas: TMyMas;
begin
TPS := TTPS.Create;
SetLength(Mas, 10);
TPS.FUN(Mas);
TPS.Free;
end;
end.
единственный глюк, который может здесь возникнуть - FUN возвращает WORD, а используется там для вычислений Integer... т.е. может, в зависимости от выполняемых действий, некорректное значение возвращать... :!!!:
ОГРОМНОЕ БЛАГОДАРЮ!!!!!!!!!!!!!
А еще такой вопрос: можно ли функцию описать как массив? например так:
function FUN(i:word): array of char;
?
А еще такой вопрос: можно ли функцию описать как массив? например так:
function FUN(i:word): array of char;
?
сам не знаю.... попробуй... только массив нужно указывать не в явном виде.... т.е.
TMyMas = Array of Char;
...
function FUN(I: Word): TMyMas;
...
сам не знаю.... попробуй... только массив нужно указывать не в явном виде.... т.е.
TMyMas = Array of Char;
...
function FUN(I: Word): TMyMas;
...
Да, получилось!Это большой прорыв - теперь у меня развязываются руки!!!
Вызов функции производится так:
...:=a(i)[j];
но это для статического массива(type TMyMas = Array[1..100] of char)!
А вот с динамическим какой-то напряг! И спец. функции для выделения памяти для массивов-функций нет!!! Может у кого-нить есть какие-нить варианты?
...:=a(i)[j];
Конечно замечательно, но если это в цикле, то хочу поздравить: ты получил жутко неэффективный код. НА КАЖДОМ i и j (т.е. i*j раз вместо i требуемых) у тебя происходит вычисление функции a(i), которая вовращает МАССИВ.
А понятия "Функция-массив" в паскале нету.
Кроме того возращать статический массив из функции как результат - жэто крайне неэффективно, ну представь, функция сначала заполяет массив, а после её вызова её массив-результат копируется в нужную переменную! Поэтому чтобы вернуть статический массив нужно использовать out- или var-параметры.
возвращать динамический массив - это уже выход. программно динамический массив представляется как указатель на область памяти, где находится сам массив (+ кое-какая инфа). Размер динамического массива получать можно функцией Length.
Т.о. лучше делать так (псевдокод):
arr - массив
a(i) возвращает динамический массив
arr:=a(i)
...
for j do begin
...arr[j]...
end;
end;
Может у кого-нить есть какие-нить варианты?
Вобщем забудь про статику.... используй динамические массивы....
размер массива i := Length(MyMas)
установка размера перед определением значений его элементов SetLength(MyMas, Size)
и ещё кое что... если массив уже имеет определённый размер, а тебе его нужно уменьшить - используй SetLength(MyMas, Length(MyMas) - 1),
а для увеличения SetLength(MyMas, Length(MyMas) + 1), при этом все элементы до Length - 1 сохраняют своё значение....