oop - 在 Fortran 中分配和构造多态对象的规范方法是什么?
问题描述
我想创建一个多态对象数组,这些对象的构造函数根据它们的动态类型采用不同的虚拟参数。在阅读了用户定义和结构构造函数之后,我发现无法将这些概念应用于动态分配的对象。有 C++ 的背景,我习惯于在动态分配对象或在堆栈上分配对象时可以使用同一个构造函数“成员函数”,但是如何在分配的对象上显式调用用户定义的 Fortran 构造函数?
相反,我试图摆弄通用和类型绑定的 init 函数:
module mod
type :: basis_t
contains
procedure, public :: init_func => init_base
! I want a generic constructor function
generic, public :: init => init_func
end type
type, extends(basis_t) :: extended_t
contains
! cannot work, init_extended has a different signature from init_base
procedure, public :: init => init_extended
end type
type wrapper_t
type(basis_t), pointer :: obj
end type
contains
subroutine init_base(this)
class(base_t), intent(inout) :: this
end subroutine
subroutine init_extended(this, param)
class(extended_t), intent(inout) :: this
integer :: param
end subroutine
end module
program
use mod
implicit none
type(wrapper_t) :: arr(2)
allocate(basis_t::arr(1)%obj)
allocate(extended_t::arr(2)%obj)
call arr(1)%obj%init ! calls init_basis
call arr(2)%obj%init(4) ! calls init_extended
end program
但我不相信我走在正确的轨道上,例如在 C++ 中,我宁愿这样做
basis_t* arr[2];
arr[0] = new basis_t;
arr[1] = new extended_t{ 4 };
重要的区别是 C++ 中的构造函数不是类型绑定/虚拟的,就像我的 Fortran 方法一样。我能做些什么?
解决方案
Fortran 中构造函数的作用可以通过以下方式提供:
该语言提供了结构构造函数。
一个函数,其结果是正在构造的对象的类型。该语言允许泛型函数与派生类型具有相同的名称,并进一步允许对此类函数的引用重载该类型的结构构造函数的引用。
定义适当类型的意图(输出)参数的子例程。
你使用什么在一定程度上取决于环境和个人喜好。语言提供的结构构造函数在某些情况下可以用在常量表达式中,但只允许对组件进行简单的值定义(没有可执行代码);函数引用形式允许您执行任意代码作为对象构造的一部分,不能在常量表达式中使用,不能轻易指示构造失败并且如果构造的对象很大,可能会很昂贵(取决于 Fortran 处理器实现细节);子例程形式需要单独的调用语句(构造函数不能是更大表达式的一部分)并且不能利用通用名称/结构重载语言功能。
这三种方法都不涉及类型绑定过程。在某些情况下,类型绑定过程可能适用于对象定义(例如,旨在从文件中读取对象值的类型绑定过程 - 扩展层次结构中的所有类型都需要有关要传递给的文件的相同信息它们),但它对构造没有一般意义,您在其中定义对象的类型以及定义其值。
Fortran 中的指针主要用于引用语义(因为它们是引用)。如果你想要值语义,你通常不想使用它们——使用可分配的。
TYPE :: ta
INTEGER :: a
END TYPE ta
TYPE, EXTENDS(ta) :: tb
REAL :: b
END TYPE :: tb
INTERFACE tb
PROCEDURE :: tb_construct
END INTERFACE tb
TYPE, EXTENDS(ta) :: tc
END TYPE tc
TYPE :: ta_item
CLASS(ta), ALLOCATABLE :: item
END TYPE ta_item
!...
FUNCTION tb_construct(arg)
INTEGER, INTENT(IN) :: arg
TYPE(tb) :: tb_construct
tb_construct%a = arg + 1
tb_construct%b = arg / 2.0
END FUNCTION tb_construct
SUBROUTINE ConstructTC(obj, arg, stat)
CLASS(ta), INTENT(OUT), ALLOCATABLE :: obj
INTEGER, INTENT(IN) :: arg
INTEGER, INTENT(OUT) :: stat
TYPE(tc), ALLOCATABLE :: tmp
IF (arg < 0) THEN
! Construction failed.
stat = 1
RETURN
END IF
tmp%a = arg + 4
CALL MOVE_ALLOC(tmp, obj)
stat = 0 ! Construction succeeded.
END SUBROUTINE ConstructTC
!...
TYPE(ta_item) :: the_items(3)
INTEGER :: stat
! Structure constructor
the_items(1)%item = ta(1)
! Overloaded function.
the_items(2)%item = tb(2)
! Subroutine.
CALL ConstructTC(the_items(3)%item, 3, stat)
IF (stat /= 0) ERROR STOP 'It failed.'
推荐阅读
- python - 使用 if 语句在 for 循环中创建 for 循环
- python - 'DataFrame' 对象没有属性 'split' 从 .csv 文件导入股票代码列表时出现问题
- ionic-framework - Google Maps Ionic Native 在 android 和 ios 中显示空白页
- php - Symfony 4环境变量未找到作曲家安装
- angular - 如何发布角度库项目?
- javascript - 如果每次更改字段数,如何验证表单数据?我正在使用 Ajax 发送表单数据
- python - 无法从系统中卸载 python - 安装过程中出现致命错误
- java - Android https请求奇怪地失败了
- laravel - 当我使用 admin Guard 登录时,如何使用名称路由提交表单?
- python - 断开一个字符串并反转它的每个元素