Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Проблема с областью видимости переменных


Автор: rodnover 29.8.2011, 11:40
Код

unit Unit2;

interface

type
  TA = class
  protected
    function func: string; virtual;
  end;

implementation

function TA.func: string;
begin
  Result := 'Test';
end;

end.



Код

unit Unit3;

interface

uses
  Unit2;

type
  TB = class(TA)
  protected
    Owner: TA;
    function func: string; override;
  public
    constructor Create(Own: TA);
  end;

implementation

{ TB }

constructor TB.Create(Own: TA);
begin
  Self.Owner := Own;
end;

function TB.func: string;
begin
  Result := Owner.func + ', Test2';    // [DCC Error] Unit3.pas(28): E2362 Cannot access protected symbol TA.func
end;

end.



По идее, класс TB наследуется от TA, следовательно он должен иметь доступ к protected методам родителя. Почему в таком случае delphi запрещает это делать (и с чем это связан этот запрет) и как можно обойти это ограничение? 

Автор: Frees 29.8.2011, 12:00
Код

Result := inherited func + ', Test2';

Автор: rodnover 29.8.2011, 12:10
Frees, не, не то. Мне именно поля Owner надо вызвать, а не Self. Я хочу декоратор сделать, но не хочу объявлять некоторые protected методы как public.

Автор: Snowy 29.8.2011, 13:09
Ты можешь обратиться к своей protected функции. но не к protected функции другого объекта, даже, если технически он ссылается на тебя.

Автор: rodnover 29.8.2011, 13:25
Придется открывать. Плохо.

Автор: sCreator 29.8.2011, 17:17
Сделай маленький хак  smile 
Код

unit Unit3;

interface
uses
  Unit2;
type
  TAHack = class(TA);

  TB = class(TA)
  protected
    Owner: TA;
    function func: string; override;
  public
    constructor Create(Own: TA);
  end;
implementation
{ TB }
constructor TB.Create(Own: TA);
begin
  Self.Owner := Own;
end;
function TB.func: string;
begin
  Result := TAHack(Owner).func + ', Test2';    // [DCC Error] Unit3.pas(28): E2362 Cannot access protected symbol TA.func
end;

end.

Автор: superVad 29.8.2011, 17:54
sCreator, 
Код

constructor TB.Create;
begin
  Self.Owner := TA.Create;
end;

?

Автор: sCreator 29.8.2011, 18:08
Цитата(superVad @  29.8.2011,  18:54 Найти цитируемый пост)
?
ответ: ваша цитата не верна - у меня такого кода нет

Автор: rodnover 29.8.2011, 20:38
sCreator, завтра попробую. Крутой хак!! Идея отличная, конечно. Спасибо!

Автор: superVad 29.8.2011, 20:57
Цитата(sCreator @  29.8.2011,  17:08 Найти цитируемый пост)
ответ: ваша цитата не верна - у меня такого кода нет

удалил лишние теги smile

Я про то - может создавать объект родитель, а не передавать?

Автор: rodnover 30.8.2011, 07:28
Цитата(superVad @  30.8.2011,  00:57 Найти цитируемый пост)
Я про то - может создавать объект родитель, а не передавать?

Это всё равно не позволит в protected метод доступ получить.

Автор: Frees 30.8.2011, 07:46
Цитата(rodnover @  29.8.2011,  16:25 Найти цитируемый пост)
Придется открывать. Плохо.


Это значит ты гдето ошибся в проектировании классов.

и это тоже признак ошибок проектирования
Цитата(sCreator @  29.8.2011,  20:17 Найти цитируемый пост)
TAHack(Owner).func


Автор: rodnover 30.8.2011, 08:38
А как тогда сделать в Делфи 2 дружественных класса не помещая их в одном модуле?

Автор: Frees 30.8.2011, 08:53
Цитата(rodnover @  30.8.2011,  11:38 Найти цитируемый пост)
А как тогда сделать в Делфи 2 дружественных класса не помещая их в одном модуле?

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

Автор: rodnover 30.8.2011, 12:43
Соглашусь на половину (чуть больше половины). Чем мне нравятся дружественные классы в С++, что класс сам определяет какие классы будут ему дружественными, в отличии от хака предложенного выше.
Это верный но способ, не не факт, что единственно правильный. ;) Всё-таки иногда считаю, что группа классов должна работать как единое целое (с точки зрения экономии строчек кода и повышения производительности).

Автор: Frees 30.8.2011, 12:45
Почитай GoF

Автор: sCreator 30.8.2011, 17:41
Цитата(Frees @  30.8.2011,  09:53 Найти цитируемый пост)
спроектировать по другому, что бы такого желания не возникало - единственно правильный способ 

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

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


Кстати описание класса TAHack лучше поместить в раздел implementation.



Автор: Frees 30.8.2011, 17:51
Цитата(sCreator @  30.8.2011,  20:41 Найти цитируемый пост)
Проектирование не нужно в зависимость от языка программирования. 

писатель на коленках, мелких поделок?

Цитата(sCreator @  30.8.2011,  20:41 Найти цитируемый пост)
Он может только внести какие то ограничения.А если проектирование загнать в жесткие рамки шаблонов и правил - это будет уже не творчество, штамповка.

а программирование это и есть штамповка по готовым шаблонам, творчество - это как объединяются эти шаблоны.

Автор: superVad 30.8.2011, 18:44
sCreator, т.е. это бок ОбжектПаскаля? В других языках есть такая возможность?
Ну - что нельзя делать дружественные классы - или как оно там называется.

Автор: sCreator 30.8.2011, 19:23
Не буду сейчас про дружественные. 
Напомню: В последних делфинах уже введен доп модификатор видимости sealed.
В C# (навскидку):
 кроме 3 основных делфийских еще комбинация с internal ( т.е. внутри сборуи ) ( а private только внутри класса, но там в классе можно объявлять вложенные классы ).
Плюс к этому частичные классы, методы расширения ...

Про бок я бы не стал так сразу.

Каждый язык начинается с концепций и развивается.
Delphi в свое время можно сказать из учебно-тренировочного языка сделали передовую среду разработки.
С++ ( ИМХО ) слишком заверчен. НО если учесть, что тогда все ручками, а он позволял двумя символами несколько строк другого языка изобразить...

Кстати а почему бы не сказать, что классы описанные в одном модуле и являются дружественными?

И почему нельзя расширить эту возможность на несколько взаимосвязанных модулей "моим хаком", если разработчик знает что делает.
Кстати при использовании "моего хака" и разнесением потомков в разные модули модель работы получается более логичной. Приватные члены хак не открывает.
И ( если не ошибаюсь ) этот хак я подсмотрел в одном из исходников Delphi.

Автор: CodeMonkey 30.8.2011, 20:33
Насколько я понимаю, понятие дружественного класса введено по той простой причине, что в языке отсутствует понятие модуля. Раз модуля нет, то появляется необходимость введения механизма для более тесной связи двух классов. Так и появляется концепция дружественных классов.

Поскольку в Delphi эту функцию тесной связи классов выполняет модуль, то дружественные классы тут просто не нужны. Соответственно, в Delphi дружественные классы - это классы одного модуля.

Откуда следует, что вопрос "как тогда сделать в Делфи 2 дружественных класса не помещая их в одном модуле?" равносилен "как тогда сделать в C++ 2 дружественных класса не делая их дружественными?"

Ответ: никак (на оба вопроса).

Автор: rodnover 31.8.2011, 07:04
Но это же большой минус, если кучу классов (пусть, даже 2) лепить в одном модуле. Модуль разрастается, ориентироваться в нём становится одно удовольствие (ирония).

 
Еще один вопрос скорее по ООП в общем, если в приведённом вначале коде заменить class TB так:

Код

unit Unit3;
interface
uses
  Unit2;
type
  TB = class(TA)
  protected
    Owner: TB;
    function func: string; override;
  public
    constructor Create(Own: TB);
  end;
implementation
{ TB }
constructor TB.Create(Own: TB);
begin
  Self.Owner := Own;
end;
function TB.func: string;
begin
  Result := Owner.func + ', Test2';  
end;
end.


Код компилируется (что логично - модуль один). Для эксперимента написал подобный код в С++ - тоже компиляция. Тогда получается что в данном случае требование

Цитата(Snowy @  29.8.2011,  17:09 Найти цитируемый пост)
Ты можешь обратиться к своей protected функции. но не к protected функции другого объекта, даже, если технически он ссылается на тебя. 


не выполняется. Почему тогда такая двойственность? Логичнее же исключить такую двойственность и быть так: либо нет допуска ко всем другим объектам (даже такого же типа) кроме public, либо ко всем объектам являющимися таким же классом или классом родителя должен быть доступ на уровне protected.

Автор: sCreator 31.8.2011, 07:18
Цитата(CodeMonkey @  30.8.2011,  21:33 Найти цитируемый пост)
"как тогда сделать в C# 2 дружественных класса не делая их дружественными?"

Я бы даже сказал: ]"как тогда сделать в C# 2 дружественных класса?" - ответ никак.
Дружественные классы, это C++ и модульности в нем гораздо больше чем в C#. 
В С++ каждый *.cpp компилируется отдельно, так же как в Delphi *.pas. А потом все линкуется.
Я бы сказал: необходимость более тесной связи классов была решена в C++ и Delphi разными способами. 

Автор: sCreator 31.8.2011, 08:28
Цитата(rodnover @  31.8.2011,  08:04 Найти цитируемый пост)
Ты можешь обратиться к своей protected функции. но не к protected функции другого объекта, даже, если технически он ссылается на тебя. 
не выполняется.


А теперь добавь к процитированной фразе еще две:
С++:
1. можно обратиться к закрытому члену объекта дружественного класса
2. класс является дружественным сам себе

Delphi:
1. можно обратиться к закрытому члену объекта класс которого описан в том же модуле ( т.е. классы определенные в одном модуле дружественные)
2. описания любых двух объектов одного класса находятся в одном модуле (класс является дружественным сам себе)

Вот твой пример и сработал.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)