Fortran Coder

标题: 隐藏派生类型的数据成员和自定义算符矛盾了怎么办? [打印本页]

作者: liudy02    时间: 2018-11-5 17:19
标题: 隐藏派生类型的数据成员和自定义算符矛盾了怎么办?
例如定义一个派生类型是三维矢量
[Fortran] 纯文本查看 复制代码
TYPE :: vect
    Real(8) ,Private :: x
    Real(8) ,Private :: y
    Real(8) ,Private :: z
End TYPE

然后希望定义矢量的数乘,并且希望可以用“*”号进行运算,
由于涉及的数据成员都是隐藏的,所以只能用绑定的方法实现
例如在派生类型定义改成:
[Fortran] 纯文本查看 复制代码
TYPE :: Vect
    Real(8) ,Private :: x
    Real(8) ,Private :: y
    Real(8) ,Private :: z
    Contains
    Generic, Public :: operator (*) => ScalMul
    Proceduce,Private :: ScalMul => VectMulScal_Fn, ScalMulVect_Fn
End TYPE
Private :: VectMulScal_Fn, ScalMulVect_Fn

然后再在模块的内部子程序列表里写出标量右乘矢量和标量左乘矢量的这两个函数实现
可是如果自定义算符要绑定类型的话,其实现方法必须是 PASS 类型的
也就导致二元算符“*”的左边必须是三元矢量的派生类型
像我刚才写的这段代码里,ScalMulVect_Fn(Scal,ThisVect)实际上根本就不被允许
可是实际矢量数乘运算时,很可能是实数在左,符号在右
所以实际上想实现的功能根本无法实现
另外,自定义算符也可以不绑定派生类型Vect
但是这样会导致其实现函数不能直接访问派生类型Vect的数据成员坐标吧?
这种情况怎么解决好呢?
我想到有两种解决办法,还请各位大神指教,也请大神有更好的办法教教我
第一种办法是不用绑定类型Vect,派生类型Vect的数据成员不设成Private,而是Protected
这样的坏处是数据成员并没有完全隐藏吧?似乎外界还是可以用Vect1%x,Vect2%y这种方法直接读数据
只是不能更改他们的值而已?这样感觉隐藏效果不佳意图没有完全实现
第二种办法也还还没办法绑定类型Vect,派生类型Vect的数据成员可以设成为Private
但是算符的实现函数ScalMulVect_Fn和VectMulScal_Fn中就不能直接引用Vect类型参量的数据成员了
只能用绑定的Get函数来读数据和用绑定的Set子程序来赋值
这个办法开起来似乎意图全都实现了,但是感觉平白多了好多函数引用,是不是会影响效率啊……
作者: pasuka    时间: 2018-11-5 21:32
SO上面的帖子,或许有所帮助
https://stackoverflow.com/questi ... n-fortran-2003-2008
https://stackoverflow.com/questi ... -types-and-override
https://softwareengineering.stac ... rtran-common-blocks
另一个思路就是参考C如何模拟面向对象,譬如GTK、GIMP这类开源框架
lz身处工业界的话,个人建议:C++改写或者混合编程,Eigen、armadillo这类线性代数模板库上手很容易
作者: 楚香饭    时间: 2018-11-5 23:12
[Fortran] 纯文本查看 复制代码
Module VectClass
  TYPE :: Vect
    Real(8) ,Private :: x
    Real(8) ,Private :: y
    Real(8) ,Private :: z
  Contains
    Procedure :: set
    Procedure,pass(ThisVect),Private :: VectMulScal_Fn , ScalMulVect_Fn , VectMulVect_Fn
    Generic, Public :: operator (*) => VectMulScal_Fn , ScalMulVect_Fn , VectMulVect_Fn
    Procedure :: writef
    Generic :: write(formatted) => writef
  End TYPE

contains

  Subroutine set(this,x,y,z)
    class(Vect) :: this
    Real(8), Intent(IN) :: x , y , z
    this%x = x ; this%y = y ; this%z = z
  End Subroutine set

  Subroutine writef(this, unit, iotype, v_list, iostat, iomsg)
    class(vect), intent(in) :: this
    integer, intent(in) :: unit
    character (len=*), intent(in) :: iotype
    integer, intent(in) :: v_list(:)
    integer, intent(out) :: iostat
    character (len=*), intent(inout) :: iomsg
    write(unit , iotype(3:) , iostat=iostat, iomsg=iomsg) this%x , this%y , this%z
   End Subroutine writef

  Type(Vect) Function ScalMulVect_Fn(ThisVect,Scal) result( y )
    real(8) , Intent(IN) :: Scal
    class(Vect) , Intent(IN) :: ThisVect
    y = Vect( ThisVect%x * Scal , ThisVect%y * Scal , ThisVect%z * Scal )
  End Function ScalMulVect_Fn

  Type(Vect) Function VectMulScal_Fn(Scal,ThisVect) result( y )
    real(8) , Intent(IN) :: Scal
    class(Vect) , Intent(IN) :: ThisVect
    y = ThisVect * Scal
  End Function VectMulScal_Fn

  Type(Vect) Function VectMulVect_Fn(ovect,ThisVect) result( y )
    class(Vect) , Intent(IN) :: ovect , ThisVect
    y = Vect( ThisVect%x * ovect%x , ThisVect%y * ovect%y , ThisVect%z * ovect%z )
  End Function VectMulVect_Fn

End Module VectClass

Program Main
  use VectClass
  type(Vect) :: a , b , c
  call a%set(1.d0,2.d0,3.d0)
  b = a * 3.0d0
  write(*,'(a,dt"(3f6.2)")') "b=" , 3.0d0*b
  c = a * ( 3.d0 * b )
  write(*,'(dt"(3f6.2)")') c
End Program Main



作者: liudy02    时间: 2018-11-6 09:57
楚香饭 发表于 2018-11-5 23:12
[mw_shl_code=fortran,true]Module VectClass
  TYPE :: Vect
    Real(8) ,Private :: x

非常感谢版主,原来可以在声明的Pass处直接用关键字申明自动传送的派生类型参量名
这样就可以改变传送的位置了,类似于Optional参量的做法
非常感谢!
版主总是一言不发,用代码直接说明问题,让人茅塞顿开,太6了!
作者: liudy02    时间: 2018-11-6 10:19
pasuka 发表于 2018-11-5 21:32
SO上面的帖子,或许有所帮助
https://stackoverflow.com/questions/19837888/protected-inheritance-in-for ...

非常感谢您的帮助
这里有些帖子确实和我有些像,也有些不同
看来Fortran做oop还是有很多问题啊
只要隐藏数据,就会带来各种各样的问题啊
而且没有真正的构造函数,看起来确实真正想做oop确实应该用c之类的
可惜我确实不是工业界的啊,而是希望用Fortran做大量科学计算的科学民工
C++的oop有时间还会再研究,现在先把Fortran用熟吧……
作者: pasuka    时间: 2018-11-7 22:02
谈不上帮忙
能够提出这类层级的问题,首先祝贺lz的Fortran水平已经跻身大中华区前5%,坏消息是后面还有OOP方面的深层次问题,恐怕直接去intel的Fortran论坛、GCC的邮件列表或者SO效果更好




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