Текущее время: Ср, апр 17 2024, 01:44

Часовой пояс: 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 часа


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

Сейчас этот форум просматривают: нет зарегистрированных пользователей


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

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