Msgstr "Метод"% s "скрывает виртуальный метод базового типа"% s ".Что на самом деле скрывается? - PullRequest
6 голосов
/ 07 октября 2010

Прочитав вопросы о конструкторе Иана Бойда ( 1 , 2 , 3 , 4 ), Я понимаю, что не совсем понимаю буквальное значение того, что скрывается.

Я знаю (поправьте меня, если я ошибаюсь) * Единственная цель override - быть способным иметь полиморфизмповедение, так что время выполнения может разрешать метод в зависимости от фактического типа экземпляра - в отличие от объявленного типа.Рассмотрим следующий код:

type
  TBase = class
    procedure Proc1; virtual;
    procedure Proc2; virtual;
  end;

  TChild = class(TBase)
    procedure Proc1; override;
    procedure Proc2;            // <- [DCC Warning]
  end;

procedure TBase.Proc1;
begin
  Writeln('Base.Proc1');
end;
procedure TBase.Proc2;
begin
  Writeln('Base.Proc2');
end;

procedure TChild.Proc1;
begin
  inherited Proc1;
  Writeln('Child.Proc1');
end;
procedure TChild.Proc2;
begin
  inherited Proc2;
  Writeln('Child.Proc2');
end;

var
  Base: TBase;
begin
  Base := TChild.Create;
  Base.Proc1;
  Writeln;
  Base.Proc2;
  Base.Free;
  Readln;
end.

Какие выходы:

Base.Proc1Child.Proc1Base.Proc2

Предупреждение о TChild.Proc2 гласит, что этот метод " скрывает доступ к методу базы с тем же именем ".Что я вижу, так это то, что если я не переопределю Proc2, я теряю способность метода разрешать его фактический тип, а не базовый тип.Как это скрывает доступ к методу базы?

Далее, в документации по предупреждению в качестве решения предупреждения указано, что:

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

Теперь, если я создам экземпляр TChild из TChild (без полиморфизма),унаследованный вызов в не переопределенном методе явно относится к исходной процедуре.Если я создаю экземпляр 'Child' из 'TBase', вызов даже не преобразуется в метод 'TChild', как я могу вызвать 'Inherited', который вообще будет ссылаться на что-либо?

Что такоеЯ недоразумение?

Ответы [ 3 ]

5 голосов
/ 07 октября 2010

Помимо всего прочего, вы не сможете определить

TGrandChild = class(TChild) 
  procedure Proc2; override;
end; 

, потому что Proc2, который видит TGrandChild, это тот из TChild, который не является виртуальным.TChild.Proc2 скрывает TBase.Proc2 от потомков.

РЕДАКТИРОВАТЬ:

В ответ на комментарий Сертака:

var 
  Base: TBase; 
  Child : TChild
begin 
  Child := TChild.Create;
  Base := Child;
  Base.Proc2; 
  Child.Proc2;

  Base.Free; 
  Readln; 

Это будет выводить

Base.Proc2
Base.Proc2
Child.Proc2

Итак, что кажется Быть вызовом одного и того же метода дважды - это фактически вызов двух разных методов.Это затрудняет понимание кода (что не практично ) и приводит к неожиданному поведению.

2 голосов
/ 07 октября 2010

Используйте «reintroduce» для подавления предупреждения.

2 голосов
/ 07 октября 2010

Вы думаете, что слишком сложно. Сокрытие не означает, что вы полностью потеряете доступ к оригиналу. Это просто означает (и вы уже отметили это сами), если у вас есть объект статического типа TChild, и вы вызываете Proc2, он вызывает тот, что в TChild, а не тот, что в TBase. Также то, что Кен сказал, правда.

Это предупреждает вас, потому что оригинал является виртуальным, и скрытие, скорее всего, не то, что люди намереваются при написании такого кода. По крайней мере, это плохой стиль кодирования.

...