Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor of derived types

I am trying to write a constructor for a derived type of an abstract one to solve this other question, but it seems that it's not working, or better, it isn't called at all.

The aim is to have a runtime polymorphism setting the correct number of legs of an animal.

These are the two modules:

animal

module animal_module
    implicit none

    type, abstract :: animal
        private
        integer, public :: nlegs = -1
    contains
        procedure :: legs
    end type animal

contains

    function legs(this) result(n)
        class(animal), intent(in) :: this
        integer :: n

        n = this%nlegs
    end function legs

cat

module cat_module
    use animal_module, only : animal
    implicit none

    type, extends(animal) :: cat
        private
    contains
        procedure :: setlegs => setlegs
    end type cat

    interface cat
        module procedure init_cat
    end interface cat

contains

    type(cat) function init_cat(this)
        class(cat), intent(inout) :: this
        print *, "Cat!"
        this%nlegs = -4
    end function init_cat

main program

program oo
    use animal_module
    use cat_module
    implicit none

    type(cat) :: c
    type(bee) :: b

    character(len = 3) :: what = "cat"

    class(animal), allocatable :: q

    select case(what)
    case("cat")
        print *, "you will see a cat"
        allocate(cat :: q)
        q = cat() ! <----- this line does not change anything

    case default
        print *, "ohnoes, nothing is prepared!"
        stop 1
    end select

    print *, "this animal has ", q%legs(), " legs."
    print *, "cat  animal has ", c%legs(), " legs."
end program

The constructor isn't called at all, and the number of legs still remains to -1.

like image 422
senseiwa Avatar asked Nov 02 '19 06:11

senseiwa


People also ask

What is constructor in derived class?

Constructors in Derived Class in C++If the class “A” is written before class “B” then the constructor of class “A” will be executed first. But if the class “B” is written before class “A” then the constructor of class “B” will be executed first.

Can derived classes have constructors?

In inheritance, the derived class inherits all the members(fields, methods) of the base class, but derived class cannot inherit the constructor of the base class because constructors are not the members of the class.


1 Answers

The available non-default constructor for the cat type is given by the module procedure init_cat. This function you have defined like

type(cat) function init_cat(this)
    class(cat), intent(inout) :: this
end function init_cat

It is a function with one argument, of class(cat). In your later reference

q = cat()

There is no specific function under the generic cat which matches that reference: the function init_cat does not accept a no-argument reference. The default structure constructor is instead used.

You must reference the generic cat in a way matching your init_cat interface to have that specific function called.

You want to change your init_cat function to look like

type(cat) function init_cat()
    ! print*, "Making a cat"
    init_cat%nlegs = -4
end function init_cat

Then you can reference q=cat() as desired.

Note that in the original, you are attempting to "construct" a cat instance, but you aren't returning this constructed entity as the function result. Instead, you are modifying an argument (already constructed). Structure constructors are intended to be used returning such useful things.

Note also that you don't need to

allocate (cat :: q)
q = cat()

The intrinsic assignment to q already handles q's allocation.

like image 191
francescalus Avatar answered Sep 29 '22 14:09

francescalus