один прикладной вопрос по ООП
Добавлено: 03.08.2012 22:31:19
Недавно мой коллега прислал мне код на C++, перевести который в FPC я так и не смог, как не бился...
Пример чисто виртуальный, никакой полезной нагрузки для практики не несёт вообще... но однако он основан на элементарщине в ООП... не понимаю почему почему FPC это не хавает... хотя Си такую вещь успешно исполняет, где у Паскаля - segmentation fail...
итак... из теории мы знаем, что методы живут отдельно от данных... в FPC почему-то не так...
вот исходный код на C++:
если кто ничерта не въезжает в подобные сишные приёмы...
с упрощением main() будет:
здесь, эта вот хитрая конструкция "Foo *foo = (Foo*)0;" происходит от того, что в Си нет автоматического преобразования из нетипизированного указателя в типизированный, по сути это просто Foo * foo = 0, но писать надо так...
и вот это в C++ собирается и работает... написать аналог в FPC мне конечно удалось... и он собирается... но не работает...
это меня и озадачило... получается, что FPC не умеет отделять мух от котлет - методы от данных...
вот мой вариант перевода:
вот, более аккуратный:
почему это не работает??? где ошибка? с точки зрения основ ООП всё сделано верно!
Похоже на то, что паскаль в этот код другую семантику вкладывает. Непонятно почему
Разыменование pointer^.data понятно является косвенной адресацией относительно адреса pointer. Но pointer^.method() семантически означает другое. Он говорит о том, что нужно взять method() относящийся к типу указателя pointer и передать ему данные по указателю pointer. И почему это не работает - не знаю. Помогите, кто чем поможет)
ещё более точно:
Операция "точка" является перегруженной и имеет совсем разный смысл при обращении к полям и методам объекта класса. Именно в этом и суть данного примера в Си++ - отличная ловушка для экзаменуемых.
Начнём с того, как они понимают операцию "точка" в только что описанном контексте.
ВЕДЬ "type_pointer^.data" и "type_pointer^.method()" - это совсем разная семантика и совершенно разная работа с указателями внутри реализации!!!
Что нужно сделать чтобы получить адрес data? Надо выполнить косвенную адресацию относительно type_pointer
А что нужно сделать чтобы получить адрес метода method()?
!!! Для этого не нужно выполнять косвенную адресацию относительно type_pointer!!!
Для этого нужно знать тип указателя, чтобы определиться с пространством имен, где надо искать адрес функции method()!!!
почему это не работает?
Пример чисто виртуальный, никакой полезной нагрузки для практики не несёт вообще... но однако он основан на элементарщине в ООП... не понимаю почему почему FPC это не хавает... хотя Си такую вещь успешно исполняет, где у Паскаля - segmentation fail...
итак... из теории мы знаем, что методы живут отдельно от данных... в FPC почему-то не так...
вот исходный код на C++:
- Код: Выделить всё
#include <iostream>
class Foo
{
public:
void foo()
{
std::cout << "hello world" << std::endl;
}
};
int main()
{
Foo& foo = *(Foo*)NULL;
foo.foo();
}
если кто ничерта не въезжает в подобные сишные приёмы...
с упрощением main() будет:
- Код: Выделить всё
int main()
{
Foo *foo = (Foo*)0;
foo->foo();
}
здесь, эта вот хитрая конструкция "Foo *foo = (Foo*)0;" происходит от того, что в Си нет автоматического преобразования из нетипизированного указателя в типизированный, по сути это просто Foo * foo = 0, но писать надо так...
и вот это в C++ собирается и работает... написать аналог в FPC мне конечно удалось... и он собирается... но не работает...
это меня и озадачило... получается, что FPC не умеет отделять мух от котлет - методы от данных...
вот мой вариант перевода:
- Код: Выделить всё
{$mode objfpc}
type
Foo = class
public
procedure foo;
end;
procedure Foo.foo;
begin
Writeln('test');
end;
var
_foo:^Foo;
begin
_foo:=nil;
_foo^.foo;
end.
вот, более аккуратный:
- Код: Выделить всё
PFoo = ^TFoo;
TFoo = class
public
procedure foo;
end;
procedure TFoo.foo;
begin
writeln('Hello world!!!');
end;
var
p: pointer;
a: PFoo;
begin
p := nil;
a := p;
a^.foo;
end.
почему это не работает??? где ошибка? с точки зрения основ ООП всё сделано верно!
Похоже на то, что паскаль в этот код другую семантику вкладывает. Непонятно почему
Разыменование pointer^.data понятно является косвенной адресацией относительно адреса pointer. Но pointer^.method() семантически означает другое. Он говорит о том, что нужно взять method() относящийся к типу указателя pointer и передать ему данные по указателю pointer. И почему это не работает - не знаю. Помогите, кто чем поможет)
ещё более точно:
Операция "точка" является перегруженной и имеет совсем разный смысл при обращении к полям и методам объекта класса. Именно в этом и суть данного примера в Си++ - отличная ловушка для экзаменуемых.
Начнём с того, как они понимают операцию "точка" в только что описанном контексте.
ВЕДЬ "type_pointer^.data" и "type_pointer^.method()" - это совсем разная семантика и совершенно разная работа с указателями внутри реализации!!!
Что нужно сделать чтобы получить адрес data? Надо выполнить косвенную адресацию относительно type_pointer
А что нужно сделать чтобы получить адрес метода method()?
!!! Для этого не нужно выполнять косвенную адресацию относительно type_pointer!!!
Для этого нужно знать тип указателя, чтобы определиться с пространством имен, где надо искать адрес функции method()!!!
почему это не работает?