Fortran Coder

标题: 子类模块为何不能重用父类模块的抽象接口? [打印本页]

作者: weixing1531    时间: 2019-7-18 21:08
标题: 子类模块为何不能重用父类模块的抽象接口?
以下代码可以正常编译运行
[Fortran] 纯文本查看 复制代码
module super_class !父类
    implicit none
    private
   
    type,public::point
        real::x=0.0
        real::y=0.0
        procedure(sub),pointer::p=>null() !过程指针作为成员变量
    contains
        procedure,pass::point_new !父类构造函数
        procedure,pass::printSum  !打印成员变量之和
    end type point

    abstract interface !抽象接口
        subroutine sub(me,x,f)
            import::point !导入宿主定义
            class(point),intent(inout)::me
            real,dimension(:), intent(in)::x
            real,intent(out)             ::f
        end subroutine sub
    end interface
contains
    subroutine point_new(me,x,y) !父类构造函数
        class(point),intent(inout)::me
        real,intent(in)::x
        real,intent(in)::y
            
        me%x=x
        me%y=y
    end subroutine point_new
   
    subroutine printSum(me,pp)
        class(point),intent(inout)::me
        procedure(sub)::pp !任何与子例程sub形参列表相同的子例程都能传入
        real::f
        
        me%p=>pp !过程指针确定指向
        call me%p([me%x,me%y],f) !相当于call me%pp()
        write(*,*)'父类sum=',f
    end subroutine printSum
end module super_class

module sub_class !子类
    use super_class
    implicit none
    private
   
    type,public,extends(point)::point3d
        real::z=0.0
    contains
        procedure,pass::point3d_new !子类构造函数
        procedure,pass::printSum !打印成员变量之和 子类重写覆盖
    end type point3d
   
    abstract interface !抽象接口
        subroutine sub(me,x,f)
            import::point !导入宿主定义
            class(point),intent(inout)::me
            real,dimension(:), intent(in)::x
            real,intent(out)             ::f
        end subroutine sub
    end interface
contains
    subroutine point3d_new(me,x,y,z) !子类构造函数
        class(point3d),intent(inout)::me
        real,intent(in)::x
        real,intent(in)::y
        real,intent(in)::z
            
        call me%point%point_new(x,y) !调用父类的构造函数
        me%z=z
    end subroutine point3d_new
   
    subroutine printSum(me,pp) !子类重写覆盖
        class(point3d),intent(inout)::me
        procedure(sub)::pp !任何与子例程sub形参列表相同的子例程都能传入
        real::f
        
        me%p=>pp !过程指针确定指向
        call me%p([me%x,me%y,me%z],f) !相当于call me%pp()
        write(*,*)'子类sum=',f
    end subroutine printSum
end module sub_class

program main !主程序
    use super_class
    use sub_class
    implicit none
   
    type(point)::a
    type(point3d)::b
   
    call a%point_new(1.0,1.0)
    call a%printSum(sss)

    call b%point3d_new(2.0,2.0,2.0)
    call b%printSum(sss)
contains   
    subroutine sss(me,x,f) !抽象接口具体实现
        class(point),intent(inout)::me
        real,dimension(:), intent(in)::x
        real,intent(out)             ::f
        
        f=sum(x)
    end subroutine sss
end program main


但是将子类模块中的抽象接口相关语句注释后
编译将报错
按理说通过use语句
子类模块可以导入父类模块相关内容  从而减少代码量
为何子类模块必须要把父类模块的抽象接口代码重写一遍呢?

作者: vvt    时间: 2019-7-18 22:03
module super_class
中添加
public :: sub
作者: weixing1531    时间: 2019-7-19 10:45
vvt 发表于 2019-7-18 22:03
module super_class
中添加
public :: sub

原来是这样
一直纳闷抽象接口怎么没有接口名
作者: lookbook    时间: 2019-7-29 22:27
赞,mark 码一下
作者: lookbook    时间: 2019-8-2 15:42
我重现了一下,其实代码上的问题,个人感觉不在类的继承上。而在于printSum上。

module m_father
  implicit none
  private
  type,public :: t_father
     procedure(temp),nopass,pointer :: p
  end type t_father

  abstract interface
     function temp(a) result(out)
       implicit none
       integer,intent(in) :: a
       integer :: out
     end function temp
  end interface
end module m_father

module m_son
  use m_father
  implicit none
  private

  type,extends(t_father),public :: t_son
     integer :: a
  end type t_son
end module m_son

program main
  use m_son
  implicit none

  type(t_son) :: one
  one%p=>jiecheng
  print*,one%p(5)

contains
  function jiecheng(a) result(out)
    implicit none
    integer,intent(in) :: a
    integer :: out

    integer :: i

    out=1
    do i=2,a
       out=out*a
    end do
  end function jiecheng
end program main

我测试了,这样是没有问题的
作者: weixing1531    时间: 2019-8-2 21:25
本帖最后由 weixing1531 于 2019-8-2 22:17 编辑
lookbook 发表于 2019-8-2 15:42
我重现了一下,其实代码上的问题,个人感觉不在类的继承上。而在于printSum上。

module m_father

你的接口是静态方法,子类没有重写父类方法
我的接口是实例方法,子类重写了父类方法,抽象接口作为实例方法形参
可能区别就在这
我的代码假如不重写父类方法也可以不用公开抽象接口

[Fortran] 纯文本查看 复制代码
module super_class !父类
    implicit none
    private
   
    type,public::point
        real::x=0.0
        real::y=0.0
        procedure(sub),pointer::p=>null() !过程指针作为成员变量
    contains
        procedure,pass::point_new !父类构造函数
        procedure,pass::printSum  !打印成员变量之和
    end type point

    abstract interface !抽象接口
        subroutine sub(me,x,f)
            import::point !导入宿主定义
            class(point),intent(inout)::me
            real,dimension(:), intent(in)::x
            real,intent(out)             ::f
        end subroutine sub
    end interface
contains
    subroutine point_new(me,x,y) !父类构造函数
        class(point),intent(inout)::me
        real,intent(in)::x
        real,intent(in)::y
            
        me%x=x
        me%y=y
    end subroutine point_new
   
    subroutine printSum(me,pp)
        class(point),intent(inout)::me
        procedure(sub)::pp !任何与子例程sub形参列表相同的子例程都能传入
        real::f
        
        me%p=>pp !过程指针确定指向
        call me%p([me%x,me%y],f) !相当于call me%pp()
        write(*,*)'父类sum=',f
    end subroutine printSum
end module super_class

module sub_class !子类
    use super_class
    implicit none
    private
   
    type,public,extends(point)::point3d
        real::z=0.0
    contains
        procedure,pass::point3d_new !子类构造函数
    end type point3d
contains
    subroutine point3d_new(me,x,y,z) !子类构造函数
        class(point3d),intent(inout)::me
        real,intent(in)::x
        real,intent(in)::y
        real,intent(in)::z
            
        call me%point%point_new(x,y) !调用父类的构造函数
        me%z=z
    end subroutine point3d_new

end module sub_class

program main !主程序
    use super_class
    use sub_class
    implicit none
   
    type(point)::a
    type(point3d)::b
   
    call a%point_new(1.0,1.0)
    call a%printSum(sss)

    call b%point3d_new(2.0,2.0,2.0)
    call b%printSum(sss)
contains   
    subroutine sss(me,x,f) !抽象接口具体实现
        class(point),intent(inout)::me
        real,dimension(:), intent(in)::x
        real,intent(out)             ::f
        
        f=sum(x)
    end subroutine sss
end program main


作者: lookbook    时间: 2019-8-3 12:32
weixing1531 发表于 2019-8-2 21:25
你的接口是静态方法,子类没有重写父类方法
我的接口是实例方法,子类重写了父类方法,抽象接口作为实例方 ...

个人感觉和重载没有关系,关键在于这是两个文件,而且有private属性,那么sub的定义只在super_class内有效。sub_class模块里的过程printsum是不知道pp的原型是什么的。你可以在sub_class内,把sub的名字改成其他,一样能通过。
作者: weixing1531    时间: 2019-8-3 17:13
lookbook 发表于 2019-8-3 12:32
个人感觉和重载没有关系,关键在于这是两个文件,而且有private属性,那么sub的定义只在super_class内有 ...

若子类成员方法的形参为父类的抽象接口,则父类模块需将其抽象接口公开
若子类模块没有使用父类的抽象接口,则父类模块不必将其抽象接口公开




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2