Δημοσιεύτηκε: 28 Μάιος 2011, 00:24
από Dimitris
Θα ήθελα να περιγράψω πολύ επιγραμματικά μερικές από τις αντικειμενοστραφείς ιδιότητες της Fortran 90/95, οι οποίες δεν είναι και τόσο γνωστές.

Καταρχήν, η χρήση modules κάνει τη διεπιφάνεια συναρτήσεων και υπορουτινών πιο καθαρή, καθώς και τη χρήση common blocks περιττή. Σε ένα αρχείο foofile.f90 γράφουμε τα εξής:

Κώδικας: Επιλογή όλων
module foo

integer :: intfoo

contains

subroutine subfoo
write(*,*) 'do something'
end subroutine

end module


και στο main.f90 έχουμε:
Κώδικας: Επιλογή όλων
program main

use foo

intfoo = 3
write(*,*) intfoo

call subfoo()

end program main

H μεταβλητή intfoo είναι μια ολική μεταβλητή του module (όχι και πολύ καθαρός τρόπος προγραμματισμου). Όπως βλέπεις όλες οι μεταβλητές και υπορουτινες του module foo είναι προσβασιμες από το κυρίως πρόγραμμα αν γράψουμε use foo. Βέβαια μέχρι στιγμής δεν κάναμε τίποτε το αντικειμενοστραφές. Τα αντικειμένα στη fortran ορίζονται ως νέοι τύποι μεταβλητών με τη βοήθεια του type.

Για παράδειγμα:

Κώδικας: Επιλογή όλων
type rectangle
real :: a, b
end type rectangle


Με αυτό ορίσαμε ένα αντικείμενο με τις ιδιότητες a, b. Σε άλλες γλώσσες προγραμματισμού θα επιτρεπόταν να ορίσουμε και μεθόδους (δηλαδή συναρτήσεις που να δρουν πάνω στο αντικείμενο, αλλα δυστυχως η fortran δεν είναι πλήρης αντικειμενοστραφής γλώσσα).

Ας δημιουργήσουμε ένα instance του αντικειμένου rectangle:

Κώδικας: Επιλογή όλων
type(rectangle) :: z

Τώρα μπορούμε να θέσουμε (set) τις ιδιότητες του αντικειμένου rectangle ως εξής:

Κώδικας: Επιλογή όλων
z%a = 1.0
z%b = 2.0


Καλή προγραμματιστική τεχνική είναι να πακετάρουμε το set σε μία "μέθοδο" του rectangle:

Κώδικας: Επιλογή όλων
subroutine set_rectangle(zloc, aloc, bloc) ! τις ονόμασα ?loc για να δείξω ότι είναι τοπικές μεταβλητές της set_rectangle

type(rectangle) :: zloc
real, intent(in) :: aloc, bloc

zloc%a = aloc
zloc%b = bloc

end

call set_rectangle(z, 1.0, 2.0)


ή ως function

Κώδικας: Επιλογή όλων
function set_rectangle(aloc, bloc)

type(rectangle) :: set_rectangle
real, intent(in) :: aloc, bloc

set_rectangle%a = aloc
set_rectangle%b = bloc

end

z = set_rectangle(1.0, 2.0)


Αντίστοιχα μπορούμε να υλοποιήσουμε τη get method ενός αντικειμένου, η οποία επιστρέφει μια ιδιότητα του αντικειμένου. Θα μπορούσαμε δηλαδή να έχουμε get_a, get_b

Κώδικας: Επιλογή όλων
print *, get_a(z) ! θα πρέπει να τυπώνει 1.0
print *, get_b(z) ! θα πρέπει να τυπώνει 2.0


Αυτό είναι ισοδύναμο με
print *, z%a
αλλά για πιο πολύπλοκα αντικείμενα ίσως είναι καλό να έχεις τις δικές τους συναρτήσεις ή μια γενική get_prop(z, 'prop')

Προχωρώντας μπορούμε να υλοποιήσουμε κι αλλές μεθόδους που εφαρμόζουν στο αντικείμενό μας, πχ εμβαδόν

Κώδικας: Επιλογή όλων
function area(x)
type(rectangle) :: x
real :: area
area = x%a * x%b
end


Τώρα υπάρχουν τρεις κατευθύνσεις στις οποίες μπορούμε να συνεχίσουμε: πολυμορφία, υπερφόρτωση τελεστών και κληρονομικότητα.

Η πολυμορφία σημαίνει ότι υλοποιούμε και το αντικείμενο circle, με τις set/get kai με τη μέθοδο area. Τώρα θέλουμε να γενικεύσουμε το πρόγραμμά μας έχοντας σχήματα, δηλαδή ένα νέο type :: shape που ανάλογα με το είδος του, θα επιλέγει ποια μέθοδο να καλέσει για αντίστοιχο σχήμα.

Η υπερφόρτωση τελεστών σημαίνει ότι μπορουμε να γράφουμε
z = x + y
όπου x, y, z είναι type :: rectangle και έχουμε ορίσει μια συνάρτηση που αντιστοιχεί στην πρόσθεση παραλληλογράμμων. Παράλληλα μπορούμε να γράψουμε
z = a*x, όπου x,z είναι type::rectangle ενώ a είναι integer ή real.

Τέλος, κληρονομικότητα είναι ίσως το αντίστοιχο της πολυμορφίας. Εχουμε δηλαδή ένα γενικό αντικείμενο, πχ shape, με τις ιδιότητες perimeter, area (προσοχή τώρα είναι ιδιότητες όχι μέθοδοι) και θέλουμε το ειδικό αντικείμενο rectangle να "κληρονομήσει" αυτές τις ιδιοτητες.

Και για να κεντρίσω το ενδιαφέρον με ένα παράδειγμα, θα μπορούσε κανείς να γράψει

Κώδικας: Επιλογή όλων
multi_stage = initialize()
do i = 1, 6
  multi_stage = multi_stage + (stator + rotor)
end do

call simulate(multi_stage)


Αυτό προϋποθέτει ότι έχουμε υπερφορτώσει τον τελεστή της πρόσθεσης ώστε να μπορεί να εφαρμόσει μια συναρτηση στα αντικείμενα stator και rotor, η οποια θα επιστρέφει ένα αντικείμενο single_stage, και ότι έχουμε υπερφορτώσει τον τελεστή της πρόσθεσης ώστε να μπορεί να εφαρμόσει μια συναρτηση στα αντικείμενα single_stage kai multi_stage, η οποία επιστρέφει ένα αντικείμενο multi_stage. Έπειτα απλά καλούμε τη μέθοδο του αντικειμένου multi_stage. Δε φαίνεται πολύ πιο ωραίος ο παραπάνω κώδικας από τον κλασσικό fortran κώδικα;