考虑一个经典的OOP示例(请参阅帖子末尾的源代码):
问题:
class(Shape), pointer :: this
作为结果为抽象类Shape定义构造函数,而不必分配指针。这是在Fortran中为抽象类定义构造函数的正确方法吗?更新了来自Ross Ridge的建议,该建议适用于非抽象基类。
module Shape_mod
implicit none
private
public Shape
type, abstract :: Shape
private
double precision :: centerPoint(2)
contains
procedure :: getCenterPoint
procedure(getArea), deferred :: getArea
end type Shape
interface Shape
module procedure constructor
end interface Shape
abstract interface
function getArea(this) result(area)
import
class(Shape), intent(in) :: this
double precision :: area
end function getArea
end interface
contains
!Correct way of defining a constructor for an abstract class?
function constructor(xCenter, yCenter) result(this)
class(Shape), pointer :: this
double precision, intent(in) :: xCenter
double precision, intent(in) :: yCenter
print *, "constructing base shape"
this%centerPoint = [xCenter, yCenter]
end function constructor
function getCenterPoint(this) result(point)
class(Shape), intent(in) :: this
double precision point(2)
point = this%centerPoint
end function getCenterPoint
end module Shape_mod
module Rectangle_mod
use Shape_mod
implicit none
private
public Rectangle
type, extends(Shape) :: Rectangle
private
double precision :: length
double precision :: width
contains
procedure :: getArea
end type Rectangle
interface Rectangle
module procedure constructor
end interface Rectangle
contains
function constructor(length, width, xCenter, yCenter) result(this)
type(Rectangle), pointer :: this
double precision :: length
double precision :: width
double precision :: xCenter
double precision :: yCenter
print *, "Constructing rectangle"
allocate(this)
this%length = length
this%width = width
!How to invoke the base class constructor here?
!The line below works for non-abstract base classes where the
!constructor result can be type(Shape)
this%Shape = Shape(xCenter, yCenter)
end function constructor
function getArea(this) result(area)
class(Rectangle), intent(in) :: this
double precision :: area
area = this%length * this%width
end function getArea
end module Rectangle_mod
program main
use Rectangle_mod
implicit none
type(Rectangle) :: r
r = Rectangle(4.0d0, 3.0d0, 0.0d0, 2.0d0)
print *, "Rectangle with center point", r%getCenterPoint(), " has area ", r%getArea()
end program main
该程序提供以下输出:
Constructing rectangle
Rectangle with center point 6.9194863361077724E-310 6.9194863361077724E-310 has area 12.000000000000000
由于尚未调用基类构造函数,因此centerPoint变量不会被初始化。在这个简单的例子中,变量可以从Rectangle构造函数手动初始化,但是对于更复杂的情况,这可能会导致代码的重复。
答案 0 :(得分:2)
这是一个很好的问题,我希望有更多经验的人可以给出更好的答案。对于第一个问题,您不需要指针,而是可以将构造函数定义为
type(Shape) function constructor(xCenter, yCenter)
double precision, intent(in) :: xCenter
double precision, intent(in) :: yCenter
print *, "constructing base shape"
constructor%centerPoint = [xCenter, yCenter]
end function constructor
对于第二个问题,答案应该是在矩形构造函数中使用行constructor%Shape = Shape(xCenter, yCenter)
调用矩形构造函数中的父项。
type(Rectangle) function constructor(length, width, xCenter, yCenter)
type(Rectangle), pointer :: this
double precision, intent(in) :: xCenter
double precision, intent(in) :: yCenter
double precision, intent(in) :: length
double precision, intent(in) :: width
print *, "Constructing rectangle"
!invoke the base class constructor here
constructor%Shape_ = Shape(xCenter, yCenter)
constructor%length = length
constructor%width = width
end function constructor
我无法使用intel编译器v13.0.1。它返回错误:If the rightmost part-name is of abstract type, data-ref shall be polymorphic
。据我所知,fortran 2008标准应该允许你调用抽象类型的构造函数,如果它是当前类型的父类。这可能适用于以后的编译器,请查看this answer(并尝试您的情况)。
如果没有,作为你想要的最小工作解决方案,我最终使用的解决方案是拥有一个定义接口的抽象形状类,然后在第一个继承了这个的对象中定义构造函数,这里是{{ 1}}类型(类似于this fortran oop示例的第11.3.2节)。解决方案如下,
shape
很抱歉,这个符号与你的例子略有不同,但希望这会有所帮助......
答案 1 :(得分:1)
"构造函数"您正在寻找的概念最好通过"初始化"一个子程序,它接受一个INTENT([IN] OUT)多态参数和抽象父类的声明类型,如Ed Smith的答案的第二部分所示。
作为概念背景 - 您不能在Fortran中创建具有抽象类型的值(这会破坏ABSTRACT的含义),但这正是您尝试使用父项的构造函数。
(这里有一个不同之处在于创建一个值,然后将该值存储在其他一些对象中。非抽象类型的值可能存储在一个多态对象中,该对象具有一个抽象的声明类型,并且是一个值类型的父类型。)