Oop Fortran中抽象基类构造函数的调用
考虑一个经典的OOP示例(请参阅本文末尾的源代码):Oop Fortran中抽象基类构造函数的调用,oop,fortran,Oop,Fortran,考虑一个经典的OOP示例(请参阅本文末尾的源代码): 抽象基类形状 类矩形扩展形状 问题: 在下面的源代码中,我尝试使用class(Shape),pointer::this为抽象类Shape定义一个构造函数,但从未分配指针。这是在Fortran中为抽象类定义构造函数的正确方法吗 如何在扩展类(矩形)的构造函数中调用基类(Shape)的构造函数 示例源代码 根据建议进行更新,该建议适用于非抽象基类 module Shape_mod implicit none private
- 抽象基类形状
- 类矩形扩展形状
class(Shape),pointer::this
为抽象类Shape定义一个构造函数,但从未分配指针。这是在Fortran中为抽象类定义构造函数的正确方法吗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变量。在这个简单的示例中,可以从矩形构造函数手动初始化变量,但对于更复杂的情况,这可能会导致代码的大量重复。这是一个好问题,我希望有更多fortran面向对象编程经验的人能给出更好的答案。对于第一个问题,您不需要指针,而是可以将构造函数定义为
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
我无法将其与英特尔编译器v13.0.1配合使用。它返回错误:如果最右边的部分名称是抽象类型,则数据引用应该是多态的
。据我所知,fortran 2008标准应该允许您调用抽象类型的构造函数(如果它是当前类型的父级)。这可能在以后的编译器中起作用,请检查(并尝试您的案例)
如果没有,作为您想要的最小工作解决方案,我最终使用的解决方案是有一个抽象的shape类来定义接口,然后在第一个对象中定义构造函数,该对象继承了这个类,这里是一个shape
类型(类似于fortran oop示例的第11.3.2节)。解决办法如下:
module shape_mod
type, abstract :: abstractshape
integer :: color
logical :: filled
integer :: x
integer :: y
end type abstractshape
interface abstractshape
module procedure initShape
end interface abstractshape
type, EXTENDS (abstractshape) :: shape
end type shape
type, EXTENDS (shape) :: rectangle
integer :: length
integer :: width
end type rectangle
interface rectangle
module procedure initRectangle
end interface rectangle
contains
! initialize shape objects
subroutine initShape(this, color, filled, x, y)
class(shape) :: this
integer :: color
logical :: filled
integer :: x
integer :: y
this%color = color
this%filled = filled
this%x = x
this%y = y
end subroutine initShape
! initialize rectangle objects
subroutine initRectangle(this, color, filled, x, y, length, width)
class(rectangle) :: this
integer :: color
logical :: filled
integer :: x
integer :: y
integer, optional :: length
integer, optional :: width
this%shape = shape(color, filled, x, y)
if (present(length)) then
this%length = length
else
this%length = 0
endif
if (present(width)) then
this%width = width
else
this%width = 0
endif
end subroutine initRectangle
end module shape_mod
program test_oop
use shape_mod
implicit none
! declare an instance of rectangle
type(rectangle) :: rect
! calls initRectangle
rect = rectangle(2, .false., 100, 200, 11, 22)
print*, rect%color, rect%filled, rect%x, rect%y, rect%length, rect%width
end program test_oop
很抱歉,符号与您的示例略有不同,但希望这将有助于…您正在寻找的“构造函数”概念最好是通过一个“初始化”子例程来实现,该子例程使用一个声明了抽象父类类型的INTENT([IN]OUT)多态参数,如Ed Smith回答的第二部分所示
作为概念背景-您不能在Fortran中创建抽象类型的值(这会破坏抽象的含义),但这正是您试图使用父级构造函数所做的
(这里的区别在于创建一个值,然后将该值存储在其他一些对象中。非抽象类型的值可能存储在一个多态对象中,该多态对象具有一个声明的抽象类型,该类型是值类型的父类型。)
type(Shape)
对于Shape
抽象类型无效。也许可以尝试class(Shape)
并使结果变量可分配。[这是否有助于回答我不知道的问题…]好建议。我不知道这个%Shape
-语法。如果我将这个%Shape=Shape(xCenter,yCenter)
添加到矩形构造函数中,它适用于非抽象基类。对于抽象类,构造函数似乎必须具有可分配的返回类型class(Shape)、指针或class(Shape)。在这种情况下,gfortran给了我一个错误:错误:无法将类(形状)转换为(1)处的类型(形状)
。编译器的抱怨对于上面显示的代码是正确的-错误消息是F2008中C611的简单结果。这个限制是适用的,因为从概念上讲,您不能有一个动态类型为抽象的对象,但这正是语法object%abstract\u parent\u type
所要求的。您好@IanH,在抽象类中为构造函数设置接口和最低要求会很有用。其他oop语言中允许使用抽象构造函数,例如java
(),c#
()。在Fortran中是否有一种语法形式可以直接执行此操作,例如allocate(this,source=this%abstract\u parent)
?根据您链接的示例,我认为您的意思是编写“抽象类的构造函数”。您不能通过当前Fortran中的过程强制定义父组件(或通过过程定义任何对象),但除此之外,抽象类的“构造函数”接口只是抽象类作者提供的过程接口。如果抽象类型作者提供了一个包含两个参数的“构造函数”子例程,那么用户不能用三个参数调用它。。。