I am trying to understand the object-oriented concepts in Fortran 2003 standards (or later). I have some knowledge in C++ so I think there are some common ideas between these two languages which can help me understand them better.
In C++, the polymorphism is done through class derivation and member function overriding. One defines a "abstract" base class where almost all the virtual functions are defined. Different derived classes contains the actual implementation of them. So other functions just need to program based on the "abstract" class. Then they works for all derived classes.
I think in Fortran, the OOP is done in a similar way but there are some differences. In my opinion, it is needed to define a base type with some virtual functions just like C++. And other functions/subroutines should follow the member function definition in the base type. That's the way of resolving the reuse of the function/subroutines for all extends types.
I don't have a better idea on how to program the idea. Here is my first attempt:
type Basis
integer :: NBasis
contains
private
procedure :: DoNothing
generic, public :: Constructor => DoNothing
generic, public :: AllocateBasis => DoNothing
endtype Basis
type, extends(Basis) :: GridBasis
private
integer :: NGrid
contains
private
procedure :: ConstructorGrid1
procedure :: ConstructorGrid2
generic, public :: Constructor => ConstructorGrid1, ConstructorGrid2, ConstructorGrid3
procedure :: AllocateGridReal
procedure :: AllocateGridCplx
generic, public :: AllocateBasis => AllocateGridReal, AllocateGridCplx
endtype GridBasis
First, how can I define the "AllocateBasis" in type Basis such that it works like the "virtual function" and all extended types must define their own version of "AllocateBasis"?
Second, how can I define "AllocateBasis" in type GridBasis? The definition here contains the real implementation of it.
Third, how can I make "AllocateBasis" in type GridBasis a overload function? i.e. there are real version and complex version and both of them are named "AllocateBasis" with real or complex input allocatable arrays.
Fourth, NOPASS vs PASS. As I understand, if PASS is set then there is a explicit pointer to the object. But when NOPASS is set, there is no such a thing. So PASS is simplify for clarification?
First some comments/answers to your questions:
You can declare a type bound procedure being
deferred
. Then you have to define its signature (interface) only without a specific implementation. The type containing thedeferred
procedure must be declaredabstract
. Such types can not be instantiated. All extending types must provide an implementation for the given procedure, unless they are themselvesabstract
.In order to provide an implementation for a
deferred
procedure in an extending type, you just declare the procedure in the extending type and provide an implementation for it.You can not turn a public procedure of a given type into a
generic
in an extending type. You can, however, define ageneric
already in the base type and extend it in its derived types.The
pass
attribute is set by default, so that the first argument of the procedure will be the type instance. You can, however, specify it to make it more explicit. Additionally, you could use it in the formPASS(ARGNAME)
to specify, which argument (ARGNAME
) should be the instance. This argument needs not be the first one in the procedure.Below you find a self containing example, which should contain all the features you asked for: