Classes are fairly new to Fortran and we will mention only a few more of their features. Some, such as inheritance, are applicable to all types. We will describe some additional features below.
One of the main purposes of OOP is to prevent outside units from doing anything without “sending a message” to an appropriate instance. As for modules, we can specify access through the PUBLIC and PRIVATE statements or attributes. As for modules, the default is PUBLIC. The previous example violates this principle. We can make everything private, which means that only members of the module can access the members of the class. We must then go through an instance of the type/class to invoke the procedures. Making a type public “exposes” the type name and its type-bound procedures, but not its variables if the module default is set to private. We will modify the example to accomplish this.
MODULE mytype_class IMPLICIT NONE PRIVATE !Everything contained is now private PUBLIC ::MyType !so need to make the type public TYPE MyType PRIVATE !Members must still be declared private INTEGER ::i,j REAL ::x,y CONTAINS PROCEDURE ::init=>init_class PROCEDURE :: write=>write_class END TYPE CONTAINS SUBROUTINE init_class(self,stuff1,stuff2) CLASS(MyType), INTENT(INOUT) :: self INTEGER, INTENT(IN) :: i1, i2 REAL, INTENT(IN) :: stuff1, stuff2 self%i=0; self%j=0 self%x=stuff1; self%y=stuff2 END SUBROUTINE SUBROUTINE write_class(self,iunit) CLASS(myType), INTENT(IN) :: self INTEGER, INTENT(IN) ::iunit WRITE(*,*) "Integers ",self%i,self%j WRITE(*,*) "Reals",self%x,self%y END SUBROUTINE SUBROUTINE reset(self,i1,i2,stuff1,stuff2) CLASS(MyType), INTENT(INOUT) :: self INTEGER, INTENT(IN) :: i1,i2 REAL, INTENT(IN) :: stuff1, stuff2 self%i=i1; self%j=i2 self%x=stuff1; self%y=stuff2 END SUBROUTINE END MODULE
In the caller: `` CALL myvar%init(i,j,x,y) CALL write_class(myvar,11) ! illegal, link error CALL myvar%write(12) ! OK
## Constructors and Destructors A _constructor_ is a subprogram that handles the bookkeeping to initialize an instance of a type. This may entail: * Assigning values to variables * Allocating memory for allocatable arrays * This _never_ happens automatically. If an allocatable is a member of a type, a constructor must be written. A _destructor_ is a subprogram that releases memory for a type. This may be required if you allocate in a constructor. The garbage collection in subprograms will not release memory allocated for a type. Fortran has no special syntax for a constructor or destructor. Programmers can define an `init` function or equivalent, then declare it `private` to be sure it can be accessed only through a type instance. Destructors can be similarly written to deallocate arrays. ## Inheritance _Inheritance_ is when a type is derived from another type and has access to its members. Inheritance is not restricted to classes in Fortran but can be used with types as well. ```fortran type Parenttype integer ::my_id real ::my_value end typeParenttype type, extends (Parenttype) :: Childtype integer ::my_int end type Childtype
The child type inherits all the attributes of its parent.
type(ChildType) :: billy billy%my_id !is valid, and is equivalent to billy%ParentType%my_id
But billy%my_int does not refer back to the parent, since that variable occurs only in the extension.
When a class is extended, not only the components but the procedures are inherited.
MODULE animal_class IMPLICIT NONE TYPE animal CHARACTER(LEN=7) :: my_name, species CONTAINS PROCEDURE :: init=>init_animal END TYPE CONTAINS SUBROUTINE init_animal(self,my_name,species) CLASS(animal), INTENT(INOUT) :: self CHARACTER(LEN=7), INTENT(IN) :: my_name, species self%my_name=my_name self%species=species END SUBROUTINE END MODULE MODULE mammal_class USE animal_class IMPLICIT NONE TYPE, EXTENDS (animal) :: mammal CHARACTER(LEN=5) :: sound CONTAINS PROCEDURE :: speak=>print_sound END TYPE CONTAINS SUBROUTINE print_sound(self,sound) CLASS(mammal), INTENT(INOUT) :: self CHARACTER(LEN=5), INTENT(IN) :: sound self%sound=sound write(*,*) trim(self%my_name)," is a ",TRIM(self%species), & " and says ",trim(self%sound)//"." END SUBROUTINE END MODULE PROGRAM zoo USE mammal_class IMPLICIT NONE TYPE(mammal) , DIMENSION(3) :: zoo_list CHARACTER(LEN=7), DIMENSION(3) :: names, species CHARACTER(LEN=5), DIMENSION(3) :: sounds INTEGER :: i names=["Raja ","Leo ","Bruno "] species=["tiger ","lion ","bear "] sounds=["chuff","roar ","growl"] DO i=1,SIZE(names) call zoo_list(i)%init(names(i),species(i)) ENDDO DO i=1,SIZE(names) call zoo_list(i)%speak(sounds(i)) ENDDO END PROGRAM
- Write a class Atom that contains the following attributes:
- Element symbol
- Element name
- Isotopic mass (mass of a single isotope, not the “atomic weight” averaged over a mix of isotopes)
- Atomic number
- The method should be
- Compute and return the number of neutrons from the mass and number (n=mass-number)