Текущее время: Чт, мар 28 2024, 17:24

Часовой пояс: UTC + 3 часа


Правила форума


ВНИМАНИЕ!

Вопросы по SAP Query и Quick View - сюда



Начать новую тему Ответить на тему  [ Сообщений: 13 ] 
Автор Сообщение
 Заголовок сообщения: ООП
СообщениеДобавлено: Вт, июн 13 2017, 11:13 
Специалист
Специалист

Зарегистрирован:
Ср, янв 26 2005, 05:11
Сообщения: 185
Пол: Мужской
Всем привет.
Есть простенька программка:
Code:
REPORT ztest_oo.
CLASS lcl_class1 DEFINITION.
  PUBLIC SECTION.
    METHODS constructor.
  PROTECTED SECTION.
    METHODS meth1.
ENDCLASS.

CLASS lcl_class1 IMPLEMENTATION.
  METHOD meth1.
    WRITE 'lcl_class1.meth1'.
  ENDMETHOD.
  METHOD constructor.
    meth1( ).
  ENDMETHOD.
ENDCLASS.

CLASS lcl_class2 DEFINITION INHERITING FROM lcl_class1.
  PROTECTED SECTION.
    METHODS meth1 REDEFINITION.
ENDCLASS.

CLASS lcl_class2 IMPLEMENTATION.
  METHOD meth1.
    WRITE 'lcl_class2.meth1'.
  ENDMETHOD.
ENDCLASS.

DATA:
lo TYPE REF TO lcl_class2.

START-OF-SELECTION.
  lo = new lcl_class2( ).

С точки зрения элементарной логики раз meth1 переопределен, то и результат должен быть lcl_class2.meth1.
А на самом деле результат lcl_class1.meth1.
Конечно, можно сделать конструктор второго класса, и там скопи-пастить конструктор первого и тогда будет все ок.
Но это же не комильфо.
Может кто-нибудь что-нибудь подскажет?


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Вт, июн 13 2017, 11:58 
Специалист
Специалист

Зарегистрирован:
Пт, июл 27 2007, 13:06
Сообщения: 137
Конструктор унаследован -> вызывается в родителе, соответственно метод вызывается родительский, а не дочерний переопределенный. Должно быть так.


Принять этот ответ
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Вт, июн 13 2017, 12:26 
Старший специалист
Старший специалист

Зарегистрирован:
Чт, май 12 2011, 16:06
Сообщения: 347
1. Лучше не вносить лишние алгоритмы в конструктор. В конструкторе должен быть только код, без которого объекты класса (а также его потомков) просто не смогут жить.
2. Конструктор не наследуется, проблема немного в другом. Конструктор вызывается при создании объекта. При этом объект строится сверху вниз: вначале создается "родительский фундамент" (вызывается конструктор предка), потом только выполняются особенности потомка. В момент вызова конструктора предка потомок еще не известен, его переопределение метода, соответственно, - тоже.


Принять этот ответ
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Ср, июн 14 2017, 04:59 
Специалист
Специалист

Зарегистрирован:
Чт, мар 25 2010, 09:02
Сообщения: 207
Нет, это просто такой абаповский "полиморфизм", в той же яве работает как надо и выводит Cl2:

Code:
public class Tst {
   public static class Cl1{
      public Cl1(){
         me1();
      }
      public void me1(){
         System.err.println("Cl1");
      }
   }
   
   public static class Cl2 extends Cl1{
      public void me1(){
         System.err.println("Cl2");
      }
   }
   
   public static void main(String[] args) {
      Cl2 cl2 = new Cl2();
   }
}


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Ср, июн 14 2017, 08:35 
Почетный гуру
Почетный гуру
Аватара пользователя

Зарегистрирован:
Пт, сен 23 2005, 11:11
Сообщения: 963
а в c++ вероятно метод базового вызовется


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Ср, июн 14 2017, 09:47 
Специалист
Специалист

Зарегистрирован:
Чт, мар 25 2010, 09:02
Сообщения: 207
trop написал(а):
а в c++ вероятно метод базового вызовется

Да, действительно, в с++ вызовется метод базового.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Ср, июн 14 2017, 10:24 
Почетный гуру
Почетный гуру
Аватара пользователя

Зарегистрирован:
Чт, дек 20 2007, 18:21
Сообщения: 1613
правильный паттерн - фабрика :D в конструкторе должна быть инициализация значений по умолчанию...

_________________
я твой сап эфай внедрял
BAdI-позитив
Взять немножечко абопу, сунь туда кошачью *опу, RFC лапки, БТ старой бабки, на медленном базиснике переносить, тестовое окружение материть, снимать SAT пенку, биться головой о стенку, охапка тайм-шитов, отчет готов!


Принять этот ответ
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Ср, июн 14 2017, 12:12 
Специалист
Специалист

Зарегистрирован:
Чт, мар 25 2010, 09:02
Сообщения: 207
Вообще даже в яве считается очень плохой практикой вызывать переопределенные методы в конструкторе.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Ср, июн 14 2017, 20:38 
Старший специалист
Старший специалист

Зарегистрирован:
Чт, май 12 2011, 16:06
Сообщения: 347
AFH написал(а):
Нет, это просто такой абаповский "полиморфизм", в той же яве работает как надо...
С тем же успехом можно утверждать, что это в яве особо одаренный полиморфизм :) (тем более, что плюсы солидарны с абапом). Явовский подход с вызовом переопределенных методов выглядит, конечно, удобным. Но вызовы методов недосозданного объекта чреваты спецэффектами.


Принять этот ответ
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Ср, июн 14 2017, 21:25 
Модератор
Модератор

Зарегистрирован:
Пн, июн 27 2011, 08:25
Сообщения: 475
1) просто так конструктор переписать не удастся, только с "нарушениями" :-)
так как в child-class должна быть конструкция super->constructor( ), которая всегда будет выполнять нужный Вам метод (или не нужный - имею ввиду метод lcl_class1->meth1).

2) а это Вы просто рассуждаете на тему ООП или есть какая-то задача (проблема), которая уперлась в эту задачу? )))

Если "край как нужно" вызвать lcl_class2->meth1 без вызова lcl_class1->meth1 (при этом возможности изменять lcl_class1 нет) то можно вот так
(такая ситуация может встречаться, когда наследование идет от стандартных классов (особенно по Industry Solutions), чтобы не иметь проблем при очередном обновлении решения)

Code:
CLASS lcl_class1 DEFINITION.
  PUBLIC SECTION.
    METHODS constructor.
  PROTECTED SECTION.
    METHODS meth1.
ENDCLASS.

CLASS lcl_class1 IMPLEMENTATION.
  METHOD meth1.
    WRITE 'lcl_class1.meth1'.
  ENDMETHOD.
  METHOD constructor.
    me->meth1( ).
  ENDMETHOD.
ENDCLASS.

CLASS lcl_class2 DEFINITION INHERITING FROM lcl_class1.
  PUBLIC SECTION.
  methods:  constructor
          , meth22
          .

  PROTECTED SECTION.
    METHODS meth1 REDEFINITION.
ENDCLASS.

CLASS lcl_class2 IMPLEMENTATION.
  METHOD constructor.
    " Компилятор скажет
    " The constructor of the superclass must not be called conditionally;
    " a preceding RETURN, EXIT or CHECK is therefore not permitted
    " но это желтое сообщение
    RETURN. """ -
    super->constructor( ).
  endmethod.
  METHOD meth1.
    WRITE 'lcl_class2.meth1'.
  ENDMETHOD.
  """""""""""""""""""""""""""""""""""""""
  method meth22.
    me->meth1( ).
  endmethod.
  """"""""""""""""""""""""""""""""""""""
ENDCLASS.

DATA:
    lo1 TYPE REF TO lcl_class1
,   lo2 TYPE REF TO lcl_class2
.

START-OF-SELECTION.
  lo2 = new lcl_class2( ).
  lo2->meth22( ).


если есть возможность поменять lcl_class1, то можно передать параметр в constructor и внести некоторые изменения в сам код
(это наиболее предпочтительный подход)

Code:
CLASS lcl_class1 DEFINITION.
  PUBLIC SECTION.
    METHODS constructor
        IMPORTING iv_mode TYPE char1 OPTIONAL
    .
  PROTECTED SECTION.
    METHODS meth1.
ENDCLASS.

CLASS lcl_class1 IMPLEMENTATION.
  METHOD meth1.
    WRITE 'lcl_class1.meth1'.
  ENDMETHOD.
  METHOD constructor.
    CASE iv_mode.
      WHEN 'A'.
        RETURN.
      WHEN '1'.
      WHEN OTHERS.
        me->meth1( ).
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_class2 DEFINITION INHERITING FROM lcl_class1.
  PUBLIC SECTION.
  methods meth22.
  PROTECTED SECTION.
    METHODS meth1 REDEFINITION.
ENDCLASS.

CLASS lcl_class2 IMPLEMENTATION.
  METHOD meth1.
    WRITE 'lcl_class2.meth1'.
  ENDMETHOD.
  """""""""""""""""""""""""""""""""""""""
  method meth22.
    me->meth1( ).
  endmethod.
  """"""""""""""""""""""""""""""""""""""
ENDCLASS.

DATA:
    lo1 TYPE REF TO lcl_class1
,   lo2 TYPE REF TO lcl_class2
.

START-OF-SELECTION.
  lo2 = new lcl_class2( 'A' ).
  lo2->meth22( ).


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Чт, июн 15 2017, 06:12 
Специалист
Специалист

Зарегистрирован:
Ср, янв 26 2005, 05:11
Сообщения: 185
Пол: Мужской
Цитата:
2) а это Вы просто рассуждаете на тему ООП или есть какая-то задача (проблема), которая уперлась в эту задачу? )))

Есть такая проблема. Есть стандартный класс, который всем подходит, за исключением некоторых параметров. Которые заполняются в конструкторе. И все бы хорошо, но только абап-ооп - не совсем ооп :( .
Выход то конечно есть, только хотелось все это сделать по проще и по красивее.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Чт, июн 15 2017, 07:19 
Модератор
Модератор

Зарегистрирован:
Пн, июн 27 2011, 08:25
Сообщения: 475
а какой выход Вы нашли?
(если можете поделиться - поделитесь, пожалуйста)

первый пример, который я предоставил выше, как раз был направлен на наследование от стандартного класса. когда-то это, так сказать, был мой выход из подобной ситуации :) . и изменение стандартного класса не потребовалось, но планировалось через грядущие ноты, поэтому пришлось так поступить.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: ООП
СообщениеДобавлено: Чт, июн 15 2017, 11:24 
Ассистент
Ассистент

Зарегистрирован:
Пт, фев 01 2013, 10:27
Сообщения: 35
Serge69 написал:
Цитата:
2) а это Вы просто рассуждаете на тему ООП или есть какая-то задача (проблема), которая уперлась в эту задачу? )))

Есть такая проблема. Есть стандартный класс, который всем подходит, за исключением некоторых параметров. Которые заполняются в конструкторе. И все бы хорошо, но только абап-ооп - не совсем ооп :( .
Выход то конечно есть, только хотелось все это сделать по проще и по красивее.


Если заполняется параметр, то что мешает перезаполнить его после отработки конструктора родителя ?
Code:
CLASS lcl_class2 IMPLEMENTATION.
  METHOD constructor.
     super->constructor( ).
     mv_par = meth1( ).
  ENDMETHOD.
...

По - моему вполне просто и наглядно )

Ну и справка сапа на эту тему явно говорит что нет обходных путей:
Цитата:
When an instance constructor is executed, the current instance temporarily assumes the type of the class in which the constructor is defined. This has the following consequences:
• If methods are called when a superclass constructor is executed, the implementations of the superclass are executed and not the redefinitions of subclasses. Specifying me->, for addressing a redefined method in a subclass that has just been generated, has no effect.
• Abstract methods of the same class cannot be called in an instance constructor.
• When a superclass constructor is executed, attempts to access components of the subclass using a down cast lead to a runtime error.


P.S. Если хочется ещё красивее, можно сделать базовый класс, который наследуется от стандартного, в нём реализовать новый конструктор, и от него наследовать все остальные - в них уже не надо будет делать конструктор :roll:


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 13 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot]


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB