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

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

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

 
 Ответить  Открыть новую тему 
> Полиморфизм + Перегруженные методы
сообщение
Сообщение #1


Я.
****

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

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


Нужно загрузить из файла объект (TTitle) наследник родителя(TPoint).

У родителя есть 2 метода:
    procedure Load(const Path: string; var fconfig: text); virtual; overload;
procedure Load(const Path, FileName: string); overload;

Реализованы так:
procedure TPoint.Load(const Path: string; var fconfig: text);
begin
//обработка файла
end;

//открытие файла
procedure TPoint.Load(const Path, FileName: string);
var
fconfig: text;
begin
assign(fconfig,Path+FileName+'\config.txt');
reset(fconfig);
Load(Path+FileName+'\',fconfig);
close(fconfig);
end;

и у наследника:
procedure TTitle.Load(const Path: string; var fconfig: text);
var
finf: text;
finfName: string;
begin
readln(fconfig);
readln(fconfig,FinfName);
inherited Load(Path,finfName);
//последующая обработка файла
end;


Проблема в том, что когда в TTitle.Load происходит inherited Load(Path,finfName); далее вызывается TPoint.Load(const Path, FileName: string); который в свою очередь вместо мной желаемого procedure TPoint.Load(const Path: string; var fconfig: text); вызывает полиморфный метод наследника TTitle.Load(const Path: string; var fconfig: text); т.е. теоретически происходит зацикливание, а практически неправильная прочитка файла.

Как эту ситуацию обойти?
Т.е. чтобы inherited Load(Path,finfName); выполнял только методы родителя или как-то так.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

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


Цитата(sheka @ 3.05.2011 21:32) *
Проблема в том, что когда в TTitle.Load происходит inherited Load(Path,finfName); далее вызывается TPoint.Load(const Path, FileName: string); который в свою очередь вместо мной желаемого procedure TPoint.Load(const Path: string; var fconfig: text); вызывает полиморфный метод наследника TTitle.Load(const Path: string; var fconfig: text);
Проблема - в том, что FPC не делает того, что ты описываешь.

Пишем простую программу, которой проверим поведение:
{$mode objfpc}

type
A = class
procedure P(const Path: string; var fconfig: text); virtual; overload;
procedure P(const Path, FileName: string); overload;
end;

B = class(A)
procedure P(const Path: string; var fconfig: text); virtual; overload;
procedure P(const Path, FileName: string); overload;
end;

procedure A.P(const Path: string; var fconfig: text);
begin
writeln('A.P (string, text)');
end;
procedure A.P(const Path, FileName: string);
var
fconfig: text;
begin
writeln('A.P (string, string)');
P(Path+FileName+'\',fconfig);
end;

procedure B.P(const Path: string; var fconfig: text);
var finfName: string;
begin
writeln('B.P (string, text)');
inherited P(Path, finfName);
end;
procedure B.P(const Path, FileName: string);
begin
writeln('B.P (string, string)');
end;

var
ObjB : B;
T : text;

begin
ObjB := B.Create;
ObjB.P('s', T);
end.
Запусти и напиши, что она тебе выдает. У меня печатается:
Running "f:\programs\pascal\oop.exe"
B.P (string, text)
A.P (string, string)
A.P (string, text)

Чувствуешь? A.P, а не B.P. Что-то не так у тебя в коде, как ты говоришь...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Я.
****

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

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


Хм..
Меня интересует чуть
другой код: (Показать/Скрыть)

который выдает в такой реализации:
A.P (string, string)
A.P (string, text)
а в
такой: (Показать/Скрыть)

Вот это:
A.P (string, string) //В вызывает родительский Р
B.P (string, text) //Создается В

A.P (string, string) //вызывается inherited
B.P (string, text) //вот здесь идет вызов метода В вместо мной желаемого А, что почему-то в вашем коде и происходит, а в моем - нет.
итд., идет зацикливание
Как вы вставляете "скрины" текстом?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

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


Цитата
//<---когда закомментировано - почему-то не работает
Оно никак не будет работать иначе. Ни когда закомментировано, ни когда раскомментировано. У класса B только один метод, который принимает две строки. И он реализован в классе A.

Разумеется, и из A.P(string, string) будет вызван именно тот P(string, text), который описан в том же A. Поскольку A.P(string, string) невиртуальный.

А вторая программа - вообще никуда не годится. Сказано было 1000 раз: когда в классе/объекте есть виртуальные методы - перед обращением к ним должен быть вызван конструктор. У тебя конструктор базового типа не вызывается (Object и Class - это не синонимы для описания эквивалентных вещей. Между ними очень много разного). ССЗБ, как говорится. Кстати, FPC 2.4.2 вообще не компилирует твою вторую программу. Он считает, что в Object-е конструктор должен именоваться Init, и никак иначе. Create не пропускается...

Цитата
Как вы вставляете "скрины" текстом?
Теги [ CONSOLE ] [ /CONSOLE ]?

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


Я.
****

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

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


Исправил, вот:
type
A = object
procedure P(const Path: string; var fconfig: text); virtual; overload;
procedure P(const Path, FileName: string); overload;
constructor Init;
end;

B = object(A)
procedure P(const Path: string; var fconfig: text); virtual;
constructor Init;
end;

procedure A.P(const Path: string; var fconfig: text);
begin
writeln('A.P (string, text)');
end;
procedure A.P(const Path, FileName: string);
var
fconfig: text;
begin
writeln('A.P (string, string)');
P(Path+FileName+'\',fconfig);
end;

procedure B.P(const Path: string; var fconfig: text);
var finfName: string;
begin
writeln('B.P (string, text)'); readln;
inherited P(Path, finfName);
end;

constructor a.Init;
begin
end;

constructor b.Init;
begin
inherited;
end;

var
ObjB : B;

begin
ObjB.Init;
ObjB.P('s', '' );
end.
Выдает тот же результат:

A.P (string, string) //В вызывает родительский Р
B.P (string, text) //Создается В

A.P (string, string) //вызывается inherited
B.P (string, text) //вот здесь идет вызов метода В вместо мной желаемого А, что почему-то в вашем коде и происходит, а в моем - нет.
итд., идет зацикливание



Добавлено через 1 мин.
Я имел ввиду как берете инфо из консоли в текстовом виде. Не вручную же забивали Running "f:\programs\pascal\oop.exe"
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

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


Да, вот с Object-ами вижу зацикливание... Попробую разобраться...

Цитата
Не вручную же забивали Running "f:\programs\pascal\oop.exe"
Нет, конечно. "Правый клик на заголовке окна -> Edit -> Mark -> выделение мышью -> Enter" никто не отменял smile.gif

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

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


М-да... Вот тебе как раз и разница между Object/Class...

Цитата(ref.pdf)
Classes have virtual methods, just as objects do. There is however a difference between the two. For objects, it is sufficient to redeclare the same method in a descendent object with the keyword virtual to override it. For classes, the situation is different: virtual methods must be overridden with the override keyword. Failing to do so, will start a new batch of virtual methods, hiding the previous one.
То есть, что происходит в случае Objects? Метод B.P(string, string) переопределил (override) метод предка A.P(string, string), этого метода A.P(string, string) в принципе нет в экземпляре типа B. Есть только A.P(string, text) и B.P(string, string)... Вот они и вызывают друг друга.

В случае классов все по-другому. Поскольку ключевого слова Override произнесено не было - метод B.P(string, string) не переопределил подобный метод из предка, а добавлен к потомку. То есть, существует и один, и второй. И программа работает как ожидается.

sheka, а зачем именно Object-ы использовать? Пользуйся классами. Они по крайней мере себя более адекватно ведут.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Я.
****

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

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


Цитата
И программа работает как ожидается.
А откуда тогда она знает когда должно выполняться "как ожидается", а когда срабатывать полиморфизм? И как вообще будет работать полиморфизм, если у предка будет 2 метода с полностью одинаковыми заголовками?

Писать заставляют в Turbo Pascale.

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

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


Цитата
Писать заставляют в Turbo Pascale.
В таком случае надо было и приводить код, который будет компилироваться в TP smile.gif Да и отлаживать код надо тоже в Турбо-Паскале. А то рискуешь в самый решающий момент нарваться на проблему: в FPC все будет в шоколаде, а TP или какого-то квалификатора знать не будет (типа Overload), либо, что еще хуже, работать будет не так, как ожидается. И будешь ловить ошибки.

Цитата
А откуда тогда она знает когда должно выполняться "как ожидается", а когда срабатывать полиморфизм? И как вообще будет работать полиморфизм, если у предка будет 2 метода с полностью одинаковыми заголовками?
Полиморфизм - это возможность передать в
procedure Polymorphic(var Obj : A);
begin
Obj.P('a', 'b');
end;

объект любого типа, производного от A и, в зависимости от типа объекта, вызывается нужный виртуальный метод. При чем он в твоем случае? У тебя тут полиморфизмом и не пахнет smile.gif Метод B.P(string, text) для возможности использования полиморфизма надо перекрыть через Override, у тебя он не перекрыт, для класса A все становится очевидно: из невиртуального метода A.P(string, string) может быть вызван только A.P(string, text)... Я ж давал тебе ссылки вроде на разжевывание ООП-модели?

Давай все-таки ближе к конкретному языку. Тебе нужно это с использованием TP? Не заморачивайся, там нет перегрузки вообще. Твой код просто напросто не откомпилируется, пока ты не поменяешь названия методам.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Я.
****

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

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


Цитата
В таком случае надо было и приводить код, который будет компилироваться в TP Да и отлаживать код надо тоже в Турбо-Паскале. А то рискуешь в самый решающий момент нарваться на проблему: в FPC все будет в шоколаде, а TP или какого-то квалификатора знать не будет (типа Overload), либо, что еще хуже, работать будет не так, как ожидается. И будешь ловить ошибки.
Уже было smile.gif как раз с Overloadом.
Цитата
Давай все-таки ближе к конкретному языку.
ТР. Так как пишу на FP, то некоторые мелочи типа Overload можно и от него. Просто различие Object/Class слишком уж велико.
Цитата
Я ж давал тебе ссылки вроде на разжевывание ООП-модели?
Вроде нет.
Цитата
Метод B.P(string, text) для возможности использования полиморфизма надо перекрыть через Override, у тебя он не перекрыт, для класса A все становится очевидно: из невиртуального метода A.P(string, string) может быть вызван только A.P(string, text)...
На это отвечу чуть позже - сейчас в голове каша.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

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

 





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