问题
This is my second question related to Fortran (I use C++, so forgive me my way of thinking).
I want to use OOP, to say, derived type in Fortran whenever appropriate. In C++, you can use user defined constructor such as https://msdn.microsoft.com/en-us/library/s16xw1a8.aspx
Here in Fortran, things are different. The first thing I tried is from here: https://www.ibm.com/developerworks/community/blogs/b10932b4-0edd-4e61-89f2-6e478ccba9aa/entry/object_oriented_fortran_user_defined_constructors2?lang=en
Then I found some other ways to do it. Here I listed a few approaches seemly to work but I only tested the first and second:
- generic interface with the same name as the derived type they're supposed to construct, see link above;
use type-bound procedure (This is not even a "traditional" constructor)
MODULE mymod TYPE mytype Private INTEGER :: x CONTAINS PROCEDURE, PASS :: init END TYPE CONTAINS SUBROUTINE init(this, i) CLASS(mytype), INTENT(OUT) :: this INTEGER, INTENT(IN) :: i write(*,*) this%x IF(i > 0) THEN this%x = 1 ELSE this%x = 2 END IF write(*,*) this%x END SUBROUTINE init END PROGRAM test USE mymod TYPE(mytype) :: y CALL y%init(1) END PROGRAMuse Static Constructors or Structure Constructors (http://www.lahey.com/docs/lfenthelp/NLMOvUsInvConst.htm) But it appears that this is NOT for general Fortran http://www.lahey.com/docs/lfenthelp/NLMGSWhatIs.htm
So I haven't understood well enough what is most preferred and flexible approach to initialize/construct a derived type in practice, especially when I use nested derived type in development. I hope I can organize this topic with some help.
回答1:
OK, so I will assume you read well the answers at How to override a structure constructor in fortran and I will answer your problem raised in the comment. There is not enough place in the comment to answer that.
You can also make constructors in Fortran which accept variable number of arguments.
It is even possible with the default structure constructors which every derived type has by default. If you default-initialize a component, it is optional in the constructor. The same holds for allocatable and pointer components.
For type
type t1
integer :: i = 1
integer, pointer :: ip => null()
integer, allocatable :: ap
end type
you can call the default constructor just as
instance = t1()
and it is perfectly legal, i will be 1, ip will point to null and ap will not be allocated.
Or you can call it as
instance = t1(ap=5)
and the ap component will be allocated and set to 5 and the other components will be left default.
You can achieve similar stuff with user defined constructors just by making the arguments optional.
function t1_user(ap, i) result(res)
type(t1) :: res
integer, allocatable :: ap !this argument MUST be passed,
! it does not have to be allocated
integer, optional :: i ! this argument is optional
if (present(i)) then
...
end if
end function
any type-bound procedure can of-course also have optional arguments.
As for the nested types, that is really best done with constructors as functions, no matter if they are default or user defined:
type inner
real :: x, y
end type
type outer
type(inner), allocatable :: in
real :: z
end type
instance1 = outer(inner(1., 2.), 3.)
instance2 = outer(z=4.)
来源:https://stackoverflow.com/questions/46570745/user-defined-constructor-for-fortran-derived-type-instance