Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop Fortran中抽象基类构造函数的调用_Oop_Fortran - Fatal编程技术网

Oop Fortran中抽象基类构造函数的调用

Oop Fortran中抽象基类构造函数的调用,oop,fortran,Oop,Fortran,考虑一个经典的OOP示例(请参阅本文末尾的源代码): 抽象基类形状 类矩形扩展形状 问题: 在下面的源代码中,我尝试使用class(Shape),pointer::this为抽象类Shape定义一个构造函数,但从未分配指针。这是在Fortran中为抽象类定义构造函数的正确方法吗 如何在扩展类(矩形)的构造函数中调用基类(Shape)的构造函数 示例源代码 根据建议进行更新,该建议适用于非抽象基类 module Shape_mod implicit none private

考虑一个经典的OOP示例(请参阅本文末尾的源代码):

  • 抽象基类形状
  • 类矩形扩展形状
问题:

  • 在下面的源代码中,我尝试使用
    class(Shape),pointer::this
    为抽象类Shape定义一个构造函数,但从未分配指针。这是在Fortran中为抽象类定义构造函数的正确方法吗
  • 如何在扩展类(矩形)的构造函数中调用基类(Shape)的构造函数
  • 示例源代码 根据建议进行更新,该建议适用于非抽象基类

    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中的过程强制定义父组件(或通过过程定义任何对象),但除此之外,抽象类的“构造函数”接口只是抽象类作者提供的过程接口。如果抽象类型作者提供了一个包含两个参数的“构造函数”子例程,那么用户不能用三个参数调用它。。。