我对Fortran OOP很新,我在初始化父类和派生类型时遇到了一些问题。我有一个模块包含父类型object
(抱歉过度使用单词..)及其派生类型circle
,它有额外的radius
字段。
我需要初始化object
类型的方法现在需要为radius使用伪参数,我想避免。所以目前我的工作方式,但我想知道一个更好的方法来做到这一点,因为如果我将来需要从object
获得更多派生类型,它似乎不太实用。
我想在这种意义上使用object
作为抽象父类型会有所帮助吗?或者使用通用程序,但我真的不知道如何做到这一点。
代码如下。
module objectMod
implicit none
type :: object
real,allocatable :: x(:,:) ! position vector (points) --- (M,{i,j})
real :: centre(2) ! centre of the object
integer :: M=50 ! number of Lagrangian points of the object (default)
real :: eps=0.1 ! kernel of the surface (default)
contains
procedure :: init=>init_object
end type object
contains
subroutine init_object(a,centre,radius,M,eps)
implicit none
class(object),intent(inout) :: a
real,intent(in) :: centre(2)
integer,intent(in),optional :: M
real,intent(in),optional :: eps
real,intent(in),optional :: radius ! ignored for object
if(present(M)) a%M = M
if(.not.allocated(a%x)) allocate(a%x(a%M,2))
a%centre = centre
if(present(eps)) a%eps = eps
end subroutine init_object
end module objectMod
module geomMod
use objectMod
implicit none
real,parameter :: PI = 3.14159265
type,extends(object) :: circle
real :: radius ! radius
contains
procedure :: init=>init_circle
end type circle
contains
subroutine init_circle(a,centre,radius,M,eps)
implicit none
class(circle),intent(inout) :: a
real,intent(in) :: centre(2)
real,intent(in),optional :: radius
integer,intent(in),optional :: M
real,intent(in),optional :: eps
integer :: i
real :: dtheta
! object type attributes initialization
a%centre = centre
if(present(M)) a%M = M
if(.not.allocated(a%x)) allocate(a%x(a%M,2))
if(present(eps)) a%eps = eps
! circle type attributes initialization
a%radius = radius
dtheta = 2.*PI/real(a%M-1)
do i = 1,a%M
a%x(i,1) = a%radius*cos(dtheta*(i-1))+a%centre(1)
a%x(i,2) = a%radius*sin(dtheta*(i-1))+a%centre(2)
end do
end subroutine init_circle
end module geomMod
答案 0 :(得分:0)
您正在做的错误是将构造函数创建为类型绑定过程。参数列表必须符合的要求是针对您的。
类型绑定过程根本不适合构造函数(或初始化程序)。
在Fortran中,我们使用返回对象实例的函数来初始化它。
function init_object(centre,M,eps) result(a)
type(object) :: a
real,intent(in) :: centre(2)
integer,intent(in),optional :: M
real,intent(in),optional :: eps
!NO radius
end function init_object
interface object
procedure init_object
end interface
....
obj = object(my_centre, my_m, my_eps)
这也是默认结构构造函数的调用方式。
我看到你从一些在线教程中取得了榜样。我觉得这个例子很糟糕。如果你不同意,你将不得不忍受它带来的这些问题。
所以,基本上,你需要一个初始化方法而不是构造函数(参见Why use an initialization method instead of a constructor?进行一些讨论。目标-C使用类似https://www.binpress.com/tutorial/objectivec-lesson-11-object-initialization/76的东西,但更新的Swift使用构造函数。)。< / p>
您可以通过这种方式使用泛型:
module types
type t1
integer :: i
contains
generic :: init => init_t1
procedure, private :: init_t1
end type
type, extends(t1) :: t2
integer :: j
contains
generic :: init => init_t2
procedure, private :: init_t2
end type
type, extends(t2) :: t3
integer :: k
contains
generic :: init => init_t3
procedure, private :: init_t3
end type
contains
subroutine init_t1(self, i)
class(t1) :: self
end subroutine
subroutine init_t2(self, i, j)
class(t2) :: self
end subroutine
subroutine init_t3(self, i, j, k)
class(t3) :: self
end subroutine
end module
在我看来,这是一个简单的丑陋和非Fortranic,但它做你想要的。
您必须特别注意用户不会因为发出错误消息的内容而过度调用错误的版本。
我的建议仍然是遵循常见的模式,而不是发明自己的方式,这会混淆那些习惯主流的人。