weixing1531 发表于 2019-7-18 21:08:11

子类模块为何不能重用父类模块的抽象接口?

以下代码可以正常编译运行
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(,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(,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:46

module super_class
中添加
public :: sub

weixing1531 发表于 2019-7-19 10:45:55

vvt 发表于 2019-7-18 22:03
module super_class
中添加
public :: sub

原来是这样
一直纳闷抽象接口怎么没有接口名

lookbook 发表于 2019-7-29 22:27:09

赞,mark 码一下

lookbook 发表于 2019-8-2 15:42:56

我重现了一下,其实代码上的问题,个人感觉不在类的继承上。而在于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:40

本帖最后由 weixing1531 于 2019-8-2 22:17 编辑

lookbook 发表于 2019-8-2 15:42
我重现了一下,其实代码上的问题,个人感觉不在类的继承上。而在于printSum上。

module m_father

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

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(,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:27

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

个人感觉和重载没有关系,关键在于这是两个文件,而且有private属性,那么sub的定义只在super_class内有效。sub_class模块里的过程printsum是不知道pp的原型是什么的。你可以在sub_class内,把sub的名字改成其他,一样能通过。

weixing1531 发表于 2019-8-3 17:13:42

lookbook 发表于 2019-8-3 12:32
个人感觉和重载没有关系,关键在于这是两个文件,而且有private属性,那么sub的定义只在super_class内有 ...

若子类成员方法的形参为父类的抽象接口,则父类模块需将其抽象接口公开
若子类模块没有使用父类的抽象接口,则父类模块不必将其抽象接口公开
页: [1]
查看完整版本: 子类模块为何不能重用父类模块的抽象接口?