Classes¶
Classes allow to combine functions with data. To exemplify classes we will make a class that is used to hold geometries and calculates the area and circumference
In [1]:
import ROOT
In [2]:
import fortranmagic
%load_ext fortranmagic
import os
import sys
import numpy as np
if sys.platform.startswith("win"):
# Depends of system, python builds, and compilers compatibility.
# See below.
f_config = "--fcompiler=gnu95 --compiler=mingw32"
else:
# For Unix, compilers are usually more compatible.
f_config = ""
# Disable only deprecated NumPy API warning without disable any APIs.
f_config += " --extra '-DNPY_NO_DEPRECATED_API=0'"
%fortran_config {f_config}
New default arguments for %fortran: --extra '-DNPY_NO_DEPRECATED_API=0'
Object oriented programming¶
c++¶
if you use a baseclass pointer as we want to do in 7.1 and 7.2. Then you need to use a default virtual destructor in the base class.
In [3]:
%%cpp -d
#include <iostream>
#include <memory>
using namespace std;
class Geometry {
public:
Geometry() {}
virtual ~Geometry() = default;//the default constructor for base class is needed
virtual double getArea() = 0;
virtual double getCircumference() = 0;
};
class Rectangle1 :public Geometry {
public:
Rectangle1(double width, double height) :width(width), height(height) {//when exist c calles the standard constructor of the parent class
}
//virtual ~Rectangle() {}//destructor if not used leave it out
virtual double getArea() override {
return width * height;
}
virtual double getCircumference() override {
return 2 * width + height;
}
protected: //can be only accessed by this class and children
private: //can only be accessed by this class
double width;
double height;
};
class Square :public Rectangle1 {
public:
Square(double l) :Rectangle1(l, l) {
}
};
class Disc :public Geometry {
public:
Disc(double r) :r(r) {
}
virtual double getArea() {
return 3.1415926 * r * r;
}
virtual double getCircumference() {
return 2 * 3.1415926 * r;
}
protected:
double r;
};
In [4]:
%%cpp
//void main()
{
Rectangle1 r(2.1, 3.1);
Square s(3.1);
Disc d(2.1);
cout << r.getArea() << endl;
cout << r.getCircumference() << endl;
cout << endl;
cout << s.getArea() << endl;
cout << s.getCircumference() << endl;
cout << endl;
cout << d.getArea() << endl;
cout << d.getCircumference() << endl;
}
6.51 7.3 9.61 9.3 13.8544 13.1947
c¶
In [5]:
%%cpp -d
#include <math.h>
typedef struct {
double width;
double height;
} Rectangle2;
typedef struct{
double r;
} Disc2;
void Rectangle_init(Rectangle2 *_this,double width, double height){
_this->width=width;
_this->height=height;
}
double Rectangle_getArea(Rectangle2 *_this){
return _this->width*_this->height;
}
double Rectangle_getCircumference(Rectangle2 *_this){
return 2*_this->width+_this->height;
}
void Square_init(Rectangle2 *_this,double r){
_this->width=r;
_this->height=r;
}
double Square_getArea(Rectangle2 *_this){
return Rectangle_getArea(_this);
}
double Square_getCircumference(Rectangle2 *_this){
return Rectangle_getCircumference(_this);
}
void Disc_init(Disc2 *_this,double r){
_this->r=r;
}
double Disc_getArea(Disc2 *_this){
return M_PI*_this->r*_this->r;
}
double Disc_getCircumference(Disc2 *_this){
return 2*M_PI*_this->r;
}
In [6]:
%%cpp
//void main(){
Rectangle2 r;
Rectangle2 s;
Disc2 d;
Rectangle_init(&r,2.1,3.1);
Square_init(&s,3.1);
Disc_init(&d,2.1);
printf("%lf\n",Rectangle_getArea(&r));
printf("%lf\n",Rectangle_getCircumference(&r));
printf("\n");
printf("%lf\n",Square_getArea(&s));
printf("%lf\n",Square_getCircumference(&s));
printf("\n");
printf("%lf\n",Disc_getArea(&d));
printf("%lf\n",Disc_getCircumference(&d));
//}
6.510000 7.300000 9.610000 9.300000 13.854424 13.194689
javascript¶
In [7]:
%%js //the next line is only necessary in jupyter notebooks
element.setAttribute('style', 'white-space: pre;');console.log=function(text){element.textContent+=text+"\n"}
class Geometry{
constructor() {
if (this.constructor == Geometry) {
throw new Error("Abstract classes can't be instantiated.");
}
}
getArea(){
throw new Error("Method 'getArea()' must be implemented.");
}
getCircumference(){
throw new Error("Method 'getCircumference()' must be implemented.");
}
}
class Rectangle extends Geometry{
constructor(width, height){
super();
this.width=width
this.height=height
}
getArea(){
return this.width*this.height;
}
getCircumference(){
return 2*this.width+this.height;
}
}
class Square extends Rectangle{
constructor(l){
super(l,l);
}
}
class Disc extends Geometry{
constructor(r){
super();
this.r=r;
}
getArea(){
return Math.PI*this.r*this.r;
}
getCircumference(){
return 2*Math.PI*this.r;
}
}
let r=new Rectangle(2.1,3.1)
let s=new Square(3.1)
let d=new Disc(2.1)
console.log(r.getArea())
console.log(r.getCircumference())
console.log("")
console.log(s.getArea())
console.log(s.getCircumference())
console.log("")
console.log(d.getArea())
console.log(d.getCircumference())
console.log("")
Python¶
In [8]:
from abc import ABC, abstractmethod
import math
class Geometry(ABC):
@abstractmethod
def getArea(self):
pass
def getCircumference(self):
pass
class Rectangle(Geometry):
def __init__(self,width, height):
self.width=width
self.height=height
super().__init__()
def getArea(self):
return self.width*self.height
def getCircumference(self):
return 2*self.width+self.height
class Square(Rectangle):
def __init__(self,l):
super().__init__(l,l);
class Disc(Geometry):
def __init__(self,r):
self.r=r
super().__init__();
def getArea(self):
return math.pi*self.r*self.r
def getCircumference(self):
return 2*math.pi*self.r;
r=Rectangle(2.1,3.1)
s=Square(3.1)
d=Disc(2.1)
print(r.getArea())
print(r.getCircumference())
print("")
print(s.getArea())
print(s.getCircumference())
print("")
print(d.getArea())
print(d.getCircumference())
print("")
6.510000000000001 7.300000000000001 9.610000000000001 9.3 13.854423602330987 13.194689145077131
Fortran 95¶
in Fortran 95 you can use structures. https://en.wikibooks.org/wiki/Fortran/structures Since Fortan 2003 you can use classes with polymorphism: https://annefou.github.io/Fortran/classes/classes.html
In [9]:
%%fortran
module test_m
implicit none
private
public test_type
type test_type
integer :: i
contains
procedure, nopass :: print_hello
procedure :: print_int
end type
contains
!> do not process type specific data => nopass
subroutine print_hello
print *, "hello"
end subroutine
!> process type specific data => first argument is "this" of type "class(test_type)"
!! use class and not type below !!!!
subroutine print_int(this)
class(test_type), intent(in) :: this
print *, "i", this%i
end subroutine
end module
! program and subroutine exchanged due to jupyternotebook
! program main
subroutine main()
use test_m
implicit none
type (test_type) :: obj
obj%i = 1 ! is like obj.i in c++,c and javascript and python
call obj%print_hello
call obj%print_int
! end program
end subroutine main
In [10]:
main()
hello i 1