2015-09-22 3 views
2

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

Так что, когда создаются моя форма решает, какой объект использовать , В этом случае я создал производный объект.

if fScreenType = ST_NewAppointment then 
    fBookingObject := TBServiceBookings.CreateServiceBookings(nil,botSingle) 
else 
    fBookingObject := TBServiceQuotes.CreateServiceQuotes(nil,botSingle); 

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

Я пробовал:

1) fBookingObject := TBServiceBookings(fBookingObject); 
    fBookingObject.SetupNewAppointmentScreen; 

2) 
    TBServiceBookings(fBookingObject).SetupNewAppointmentScreen; 

3) 
    (fBookingObject as TBServiceBookings).SetupNewAppointmentScreen; 

Что мне не хватает? Почему производный метод вызывается каждый раз, даже несмотря на то, что я специально отключил вызов базового метода?

Единственное, что у меня осталось - это создать новую переменную базового типа, а затем продолжить с этим. Но у меня уже есть переменная формы, которая является моим объектом, я просто хочу вызвать метод базового класса.

Любая помощь приветствуется!

+0

Ваш код является неполным, поэтому мы не можем увидеть, правильно ли установлен «SetupNewAppointmentScreen» как «виртуальный» в базовом классе и «переопределить» в дочернем классе –

+1

. Я предполагаю, что метод, который вы называете, является виртуальным (или динамическим). Затем он всегда вызывает метод * actual * type, а не типа * объявленного *. Кастинг не меняет этого. Тот факт, что вы хотите назвать поведение базового класса, означает, что вы, вероятно, должны пересмотреть свой дизайн. –

+0

@Stefan: тогда он будет вести себя так, как он хочет, или имеет поведение самого производного класса, который сделал это правильно. Если он виртуальный и правильно помечен как переопределяющий, он делает то, что он описывает. Но необходимость называть поведение базового класса - это ИМО, запах кода. –

ответ

3

Помимо вопроса, который стоит за вашим вопросом «где вам нужна эта необычная и несколько подозрительная конструкция для?», Есть некоторые возможности для доступа к виртуальному методу предка.

  1. Действительно некрасиво: изменить тип компонента:

    var 
        SaveType: TClass; 
    begin 
        SaveType := Self.ClassType; 
        PClass(Self)^ := TAncestor; 
        try 
        Self.AncestorMethod; 
        finally 
        PClass(Self)^ := SaveType 
        end; 
    end; 
    
  2. Cast метод вместо класса:

    type 
        TInstanceMethod = procedure(Instance: TObject); 
    
    begin 
        TInstanceMethod(@TAncestor.AncestorMethod)(Self); 
    end; 
    
  3. Наймите класса помощника:

    type 
        TAncestorHelper = class helper for TAncestor 
        procedure AncestorMethodViaHelper; 
        end; 
    
    procedure TAncestorHelper.AncestorMethodViaHelper; 
    begin 
        inherited AncestorMethod; 
    end; 
    
    begin 
        Self.AncestorMethodViaHelper; 
    end; 
    

При необходимости я всегда использую второе решение. Но это только при общении с предками, которые я не могу изменить, например. VCL. В ваших собственных рамках вам никогда не понадобятся эти хаки, потому что вы можете просто перепроектировать.

+0

Благодарим вас за советы NGLN –

1

Ну, если класс принадлежит вам, у вас есть полный контроль, поэтому просто не переопределяйте базовый метод, который вы хотите вызвать. Нравится:

fBaseObject.ThisMethodBase; { calls the original } 
fDerivedObject.ThisMethod; { calls the new one } 

Похоже, это самый простой способ сделать это. Также помните, что вы можете просто вызвать метод Inherited из вашего метода overriden. Поэтому, если вы хотите получить объявление, вы можете передать логическое значение, указывающее, хотите ли вы базовую функциональность. Нравится:

type 
TX1=class 
    function ThisMethod(whatever:Integer;callOldOne:Boolean=false):integer;virtual; 
end; 

TX2=class(TX1) 
    function ThisMethod(whatever:Integer;callOldOne:Boolean=false):integer;override; 
end; 

function TX1.ThisMethod(whatever:Integer;callOldOne:Boolean=false):integer; 
begin 
    result:=1; 
end; 

function TX2.ThisMethod(whatever:Integer;callOldOne:Boolean=false):integer; 
begin 
    if callOldOne then result:=inherited ThisMethod(whatever) else Result:=2; 
end; 

Объектно-ориентированное программирование - это весело.

+0

Thanx Kung Lao. Это, казалось, превзошло цель того, что я пытался сделать. Я хотел, чтобы объект знал, что делать по его типу. Я разделил логику на базовый и производный класс, и я хотел, чтобы объект обрабатывал его соответствующим образом. –