Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Abstract classes and constructors - cannot call abs. methods in CONSTRUCTOR

alejandro_bindi
Active Contributor
0 Kudos
1,118

Let me explain the scenario:

I'm building a program in which I need to read a file (among other things) and I intend to use object orientation to it's fullest in doing so. I thought of creating an abstract FILE class which has the commonalities, and two subclasses SERVER_FILE and PC_FILE, which implement the abstract method GET_CONTENTS in different ways (OPEN DATASET / GUI_UPLOAD), same for the CHOOSE method which allows to select the file from it's corresponding source.

Initially I've used an interface but since another tasks like setting the file path are common for both, switched to an ABSTRACT class.

Now, the problem is, from the main code I intend to use a FILE reference to handle either type of file. At the instantiation moment I'd like the path attribute to be set; if it was not set by parameter, i'd like to call the CHOOSE method which is abstract for the superclass. Since this is common for either subclass, I need a way to code it once in the superclass. But I get an error because the CHOOSE method is abstract.

This is the problem code (extracts):


*---------------------------------------------------------------------*
*       CLASS lcl_file DEFINITION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_file DEFINITION ABSTRACT.
  PUBLIC SECTION.
    METHODS:
      constructor
        IMPORTING
          i_path  TYPE string OPTIONAL
        EXCEPTIONS
          no_path_chosen,
      get_contents ABSTRACT
        RETURNING
          value(rt_contents) TYPE string_table
        EXCEPTIONS
          read_error.
  PROTECTED SECTION.
    DATA:
      _v_path        TYPE string.
    METHODS:
      choose ABSTRACT
        EXCEPTIONS
          no_path_chosen,
      set_path
        IMPORTING
          i_path  TYPE string.
ENDCLASS.                    "lcl_file DEFINITION

*---------------------------------------------------------------------*
*       CLASS lcl_file IMPLEMENTATION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_file IMPLEMENTATION.
  METHOD constructor.
    IF i_path IS SUPPLIED.
      CALL METHOD set_path
        EXPORTING
          i_path = i_path.
    ELSE.
*---->>>> PROBLEM CALL - CAN'T BE DONE!!
      CALL METHOD choose
        EXCEPTIONS
          no_path_chosen = 1.
      IF sy-subrc = 1.
        RAISE no_path_chosen.
      ENDIF.
    ENDIF.
  ENDMETHOD.                    "constructor

  METHOD set_path.
    _v_path = i_path.
  ENDMETHOD.                    "set_path
ENDCLASS.                    "lcl_file IMPLEMENTATION

*---------------------------------------------------------------------*
*       CLASS lcl_server_file DEFINITION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_server_file DEFINITION
                      INHERITING FROM lcl_file.
  PUBLIC SECTION.
    METHODS:
      get_contents REDEFINITION.
  PROTECTED SECTION.
    METHODS:
      choose       REDEFINITION.
ENDCLASS.                    "lcl_server_file  DEFINITIO

*---------------------------------------------------------------------*
*       CLASS lcl_server_file IMPLEMENTATION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_server_file IMPLEMENTATION.

  METHOD choose.
    DATA:
      l_i_path     TYPE dxfields-longpath,
      l_o_path     TYPE dxfields-longpath.

    CALL FUNCTION 'F4_DXFILENAME_TOPRECURSION'
      EXPORTING
        i_location_flag = 'A'  " Application server
        i_path          = l_i_path
        fileoperation   = 'R'  " Lectura
      IMPORTING
        o_path          = l_o_path
      EXCEPTIONS
        rfc_error       = 1
        OTHERS          = 2.
    IF sy-subrc = 0 AND l_o_path <> l_i_path.
      MOVE l_o_path TO _v_path.
    ELSE.
      RAISE no_path_chosen.
    ENDIF.
  ENDMETHOD.                    "choose

  METHOD get_contents.
    DATA: l_line   LIKE LINE OF rt_contents,
          l_osmsg  TYPE string.

    CHECK NOT _v_path IS INITIAL.
    OPEN DATASET _v_path FOR INPUT
                             IN TEXT MODE
                             MESSAGE l_osmsg.
    IF sy-subrc <> 0.
      MESSAGE e000(oo) WITH l_osmsg
                       RAISING read_error.
    ELSE.
      DO.
        READ DATASET _v_path INTO l_line.
        IF sy-subrc = 0.
          APPEND l_line TO rt_contents.
        ELSE.
          EXIT.
        ENDIF.
      ENDDO.

      CLOSE DATASET _v_path.
    ENDIF.
  ENDMETHOD.                    "get_contents
ENDCLASS.                    "lcl_server_file IMPLEMENTATION

*---------------------------------------------------------------------*
*       CLASS lcl_pc_file DEFINITION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_pc_file  DEFINITION
                   INHERITING FROM lcl_file.
  PUBLIC SECTION.
    METHODS:
      get_contents REDEFINITION.
  PROTECTED SECTION.
    METHODS:
      choose       REDEFINITION.
ENDCLASS.                    "lcl_pc_file  DEFINITIO

*---------------------------------------------------------------------*
*       CLASS lcl_pc_file IMPLEMENTATION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_pc_file IMPLEMENTATION.

  METHOD choose.
    DATA:
      l_i_path     TYPE dxfields-longpath VALUE 'C:\',
      l_o_path     TYPE dxfields-longpath.

    CALL FUNCTION 'F4_DXFILENAME_TOPRECURSION'
      EXPORTING
        i_location_flag = 'P'  " PC
        i_path          = l_i_path
        fileoperation   = 'R'  " Lectura
      IMPORTING
        o_path          = l_o_path
      EXCEPTIONS
        rfc_error       = 1
        OTHERS          = 2.
    IF sy-subrc = 0 AND l_o_path <> l_i_path.
      MOVE l_o_path TO _v_path.
    ELSE.
      RAISE no_path_chosen.
    ENDIF.
  ENDMETHOD.                    "choose

  METHOD get_contents.
    CHECK NOT _v_path IS INITIAL.

    CALL METHOD cl_gui_frontend_services=>gui_upload
      EXPORTING
        filename                = _v_path
      CHANGING
        data_tab                = rt_contents
      EXCEPTIONS
        file_open_error         = 1
        file_read_error         = 2
        no_batch                = 3
        gui_refuse_filetransfer = 4
        invalid_type            = 5
        no_authority            = 6
        unknown_error           = 7
        bad_data_format         = 8
        header_not_allowed      = 9
        separator_not_allowed   = 10
        header_too_long         = 11
        unknown_dp_error        = 12
        access_denied           = 13
        dp_out_of_memory        = 14
        disk_full               = 15
        dp_timeout              = 16
        OTHERS                  = 17.
    IF sy-subrc <> 0.
      RAISE read_error.
    ENDIF.
  ENDMETHOD.                    "get_contents
ENDCLASS.                    "lcl_pc_file IMPLEMENTATION


*----------------------------------------------------------------------*
* Data
*----------------------------------------------------------------------*
DATA: gr_file          TYPE REF TO lcl_file.

*-----------------------------------------------------------------------
* Main Program
*-----------------------------------------------------------------------

START-OF-SELECTION.

*   Get text lines from file
    IF p_srv = abap_true.
      CREATE OBJECT gr_file
        TYPE
          lcl_server_file
        EXCEPTIONS
          no_path_chosen  = 1.
    ELSE.
      CREATE OBJECT gr_file
        TYPE
          lcl_pc_file
        EXCEPTIONS
          no_path_chosen = 1.
    ENDIF.

On a 4.6c system this code gave me a dump, while on my NW7.0 SP it doesn't even activate with the following error:

You cannot call abstract methods in the "CONSTRUCTOR" method.

- Following some suggestions from Java forums i've tried to define the constructor in the base class as PROTECTED or PRIVATE instead, then calling super->constructor from the subclasses, but I get this error in german:

Sichtbarkeit des Konstruktors darf nicht spezieller als die Sichtbarkeit der Instanzerzeugung (CREATE-Zuzatz) sein.

which Altavista translates like:

Visibility of the constructor may not be more special than the

visibility of the instance production (CREATE Zuzatz).

- I've also thought of defining the CHOOSE method as a class (not instance) one, then calling it before creating the file object which maybe solves the problem, but I see that approach more "procedural oriented" which i'm trying to avoid.

- Of course I could define a constructor for each subclass, but both would have exactly the same code.

I'm really lost on how should I code this. My main focus is on avoiding code dupplication.

I hope someone with more OO experience can see what I'm trying to do and sheds some light.

Many thanks for reading all this!

3 REPLIES 3

Former Member
0 Kudos
208

Hi Alejandro,

I tried some changes in your code and atleast got rid of your error

" You cannot call abstract methods in the "CONSTRUCTOR" method. "

heres how ....

1) Change One--


in cunstructor definition-----

CLASS lcl_file DEFINITION ABSTRACT.

PUBLIC SECTION.

METHODS:

constructor

IMPORTING

i_path TYPE string OPTIONAL

i_ref TYPE REF TO lcl_file ">>>>>>>> gaurav

EXCEPTIONS

no_path_chosen,

;

;

2) Change TWO--


in calling CHOOSE method--


CALL METHOD i_ref->choose ">>>>>>>> gaurav

3) Change THREE--


in START OF SELECTION--

defined two more reference variables as

DATA: gr_file TYPE REF TO lcl_file. "declared by YOU

DATA gr_server_file TYPE REF TO lcl_server_file.

DATA gr_pc_file TYPE REF TO lcl_pc_file.

START-OF-SELECTION.

  • Get text lines from file

IF p_srv = abap_true.

CREATE OBJECT gr_server_file. ">>>>>>>> gaurav

CREATE OBJECT gr_file

TYPE

lcl_server_file

EXPORTING

i_ref = gr_server_file ">>>>>>>> gaurav

EXCEPTIONS

no_path_chosen = 1.

ELSE.

create object gr_pc_file. ">>>>>>>> gaurav

CREATE OBJECT gr_file

TYPE

lcl_pc_file

exporting

iref = gr_pc_file ">>>>>>>> gaurav

EXCEPTIONS

no_path_chosen = 1.

ENDIF.

4) After this I got some error in the If condition in

" IF sy-subrc = 0 AND l_o_path EQ l_i_path. " I added the EQ

5) When changed this also I got error for .....

OPEN dataset STATEMENT..... of GET_CONTENTs method....

addiding "ENCODING DEFAULT WITH SMART LINEFEED" at the end of this open dataset statement .....there are other errors

6) like IF sy-subrc 0. without EQ or NE operator.......

I didn't do much changes there after..... You can get those all sorted.

Hope this helps,

Regds,

Gaurav

Edited by: Gaurav P Fadnis on Mar 19, 2008 10:57 AM

Former Member
0 Kudos
208

Dear Alejandro,

When i saw your code, you are trying to access an astract method CHOOSE(which is actually implemented in sub class) from the constructor of the base class which is not possible. By this time, we don't know which sub class it is refering to, so it gives an error. I see two solutions for this..

1. To define constructor in sub class and call the choose method from the consturctor of the sub class(which in this case is reputation of the same again for each sub class)

2. Remove the calling of choose method from the constructor of the main class and call it separately(after creating the object). By now we know which sub class we are refering to. I would have designed the program in the following way.

*---------------------------------------------------------------------*
*       CLASS lcl_file DEFINITION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_file DEFINITION ABSTRACT.
  PUBLIC SECTION.
    METHODS:
      constructor
        IMPORTING
          i_path  TYPE string OPTIONAL
        EXCEPTIONS
          no_path_chosen,
      get_contents ABSTRACT
        RETURNING
          value(rt_contents) TYPE string_table
        EXCEPTIONS
          read_errorm,
      set_path ABSTRACT
        EXCEPTIONS
          no_path_chosen.

  PROTECTED SECTION.
    DATA:
      _v_path        TYPE string.
*    METHODS:
*      choose ABSTRACT
*        EXCEPTIONS
*          no_path_chosen,
*      set_path ABSTRACT
*        IMPORTING
*          i_path  TYPE string.
ENDCLASS.                    "lcl_file DEFINITION

*---------------------------------------------------------------------*
*       CLASS lcl_file IMPLEMENTATION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_file IMPLEMENTATION.
  METHOD constructor.
    IF i_path IS SUPPLIED.
      _v_path = i_path.
*      CALL METHOD set_path
*        EXPORTING
*          i_path = i_path.
*    ELSE.
**---->>>> PROBLEM CALL - CAN'T BE DONE!!
*      CALL METHOD choose
*        EXCEPTIONS
*          no_path_chosen = 1.
*      IF sy-subrc = 1.
*        RAISE no_path_chosen.
*      ENDIF.
    ENDIF.
  ENDMETHOD.                    "constructor

* METHOD set_path.
*    _v_path = i_path.
* ENDMETHOD.                    "set_path
ENDCLASS.                    "lcl_file IMPLEMENTATION

*---------------------------------------------------------------------*
*       CLASS lcl_server_file DEFINITION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_server_file DEFINITION
                      INHERITING FROM lcl_file.
  PUBLIC SECTION.
    METHODS:
      get_contents REDEFINITION,
      set_path     REDEFINITION.
*  PROTECTED SECTION.
*    METHODS:
*      choose       REDEFINITION.
ENDCLASS.                    "lcl_server_file  DEFINITIO

*---------------------------------------------------------------------*
*       CLASS lcl_server_file IMPLEMENTATION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_server_file IMPLEMENTATION.

  METHOD set_path.
    DATA:
      l_i_path     TYPE dxfields-longpath,
      l_o_path     TYPE dxfields-longpath.

    CHECK _v_path IS INITIAL.

    CALL FUNCTION 'F4_DXFILENAME_TOPRECURSION'
      EXPORTING
        i_location_flag = 'A'  " Application server
        i_path          = l_i_path
        fileoperation   = 'R'  " Lectura
      IMPORTING
        o_path          = l_o_path
      EXCEPTIONS
        rfc_error       = 1
        OTHERS          = 2.
    IF sy-subrc = 0 AND l_o_path  = l_i_path.
      MOVE l_o_path TO _v_path.
    ELSE.
      RAISE no_path_chosen.
    ENDIF.
  ENDMETHOD.                    "set_path

  METHOD get_contents.
    DATA: l_line   LIKE LINE OF rt_contents,
          l_osmsg  TYPE string.

    CHECK NOT _v_path IS INITIAL.
*    OPEN DATASET _v_path FOR INPUT
*                             IN TEXT MODE
*                             MESSAGE l_osmsg.
    IF sy-subrc  = 0.
*      MESSAGE e000(oo) WITH l_osmsg
*                       RAISING read_error.
    ELSE.
      DO.
        READ DATASET _v_path INTO l_line.
        IF sy-subrc = 0.
          APPEND l_line TO rt_contents.
        ELSE.
          EXIT.
        ENDIF.
      ENDDO.

      CLOSE DATASET _v_path.
    ENDIF.
  ENDMETHOD.                    "get_contents
ENDCLASS.                    "lcl_server_file IMPLEMENTATION

*---------------------------------------------------------------------*
*       CLASS lcl_pc_file DEFINITION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_pc_file  DEFINITION
                   INHERITING FROM lcl_file.
  PUBLIC SECTION.
    METHODS:
      get_contents REDEFINITION,
      set_path     REDEFINITION.
*  PROTECTED SECTION.
*    METHODS:
*      choose       REDEFINITION.
ENDCLASS.                    "lcl_pc_file  DEFINITIO

*---------------------------------------------------------------------*
*       CLASS lcl_pc_file IMPLEMENTATION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_pc_file IMPLEMENTATION.

  METHOD set_path.
    DATA:
      l_i_path     TYPE dxfields-longpath VALUE 'C:\',
      l_o_path     TYPE dxfields-longpath.

    CHECK _v_path IS INITIAL.

    CALL FUNCTION 'F4_DXFILENAME_TOPRECURSION'
      EXPORTING
        i_location_flag = 'P'  " PC
        i_path          = l_i_path
        fileoperation   = 'R'  " Lectura
      IMPORTING
        o_path          = l_o_path
      EXCEPTIONS
        rfc_error       = 1
        OTHERS          = 2.
    IF sy-subrc = 0 AND l_o_path  = l_i_path.
      MOVE l_o_path TO _v_path.
    ELSE.
      RAISE no_path_chosen.
    ENDIF.
  ENDMETHOD.                    "set_path

  METHOD get_contents.
    CHECK NOT _v_path IS INITIAL.

    CALL METHOD cl_gui_frontend_services=>gui_upload
      EXPORTING
        filename                = _v_path
      CHANGING
        data_tab                = rt_contents
      EXCEPTIONS
        file_open_error         = 1
        file_read_error         = 2
        no_batch                = 3
        gui_refuse_filetransfer = 4
        invalid_type            = 5
        no_authority            = 6
        unknown_error           = 7
        bad_data_format         = 8
        header_not_allowed      = 9
        separator_not_allowed   = 10
        header_too_long         = 11
        unknown_dp_error        = 12
        access_denied           = 13
        dp_out_of_memory        = 14
        disk_full               = 15
        dp_timeout              = 16
        OTHERS                  = 17.
    IF sy-subrc  = 0.
*      RAISE read_error.
    ENDIF.
  ENDMETHOD.                    "get_contents
ENDCLASS.                    "lcl_pc_file IMPLEMENTATION


*----------------------------------------------------------------------*
* Data
*----------------------------------------------------------------------*
DATA: gr_file          TYPE REF TO lcl_file.

*-----------------------------------------------------------------------
* Main Program
*-----------------------------------------------------------------------

START-OF-SELECTION.

*   Get text lines from file
  IF abap_true = abap_true.
    CREATE OBJECT gr_file
      TYPE
        lcl_server_file
      EXCEPTIONS
        no_path_chosen  = 1.
  ELSE.
    CREATE OBJECT gr_file
      TYPE
        lcl_pc_file
      EXCEPTIONS
        no_path_chosen = 1.
  ENDIF.

  gr_file->set_path( ).

Regards

Kesava

Edited by: Kesava Chandra Rao on Mar 19, 2008 11:44 AM

alejandro_bindi
Active Contributor
0 Kudos
208

Hello,

Many thanks to both for taking the time to help.

Here go my replies:

@Gaurav: Your changes 1 to 3 surely work, but as I said I intend to have only an lcl_file reference, which polimorphically knows how to execute the GET_CONTENTS and CHOOSE methods (depending on how it was instantiated at runtime rather than how was declared statically).

The 4th error was caused by the forum, the = was there but the formatting tag removed it somehow 😮

The remaining errors you got (like with the OPEN DATASET) are probably caused because i'm coding this on a 4.6C system, which may have other obsolete statements. Hence the ugly "CALL METHOD" syntax everywhere. I intend to finish the code on this system and then port it to 7.0.

@Kesava: I think I'll go with the first option...the way I'm thinking of a File object (as merely a file pointer, which doesn't hold the contents) implies that when created, it should have the path set by any means. That's why I don't like to have to call a method afterwards to do it, I see it like a second "initialization" which shouldn't be necessary.