(由于我对Fortran OOP功能还很陌生,以下答案可能包含一些大错误,所以请小心...用gfortran4.8.2测试)
首先在B_new_Constructor() 中,this 作为第一个参数给出,但没有明确声明(可能是错字)。因为没有implicit none,所以这个隐式this 不会发生错误。此外,据我了解,Fortran 的“构造函数”不是派生类型的成员函数,而是通常指一个模块过程,该过程用默认结构构造函数重载以返回新对象。因此,无需将this 传递给用户定义的构造函数(此处为B_new_Constructor()),而是期望返回一个新构造的对象。
用原代码,这样的主程序
program main
use B_module, only: A, B_new
type(B_new) :: p, q, r
p = B_new()
print *, "p = ", p
q = B_new( [ A(1.0d0,2.0d0), A(3.0d0,4.0d0) ] )
print *, "q = ", q
r = B_new( [ A(1.0d0,2.0d0), A(3.0d0,4.0d0) ], [ 5.0d0, 6.0d0 ] )
print *, "r = ", r
end
给出类似的错误消息
p = B_new()
1
Error: No initializer for component 'a_list' given in the structure constructor at (1)!
q = B_new( [ A(1.0d0,2.0d0), A(3.0d0,4.0d0) ] )
1
Error: No initializer for component 'feature' given in the structure constructor at (1)!
现在如果我们在B_module 的顶部附加implicit none 并将B_new_Constructor() 更改为
function B_new_Constructor( A_listInput ) result( ret )
type(A) :: A_listInput( 2 )
type(B_new) :: ret
print *, "modified constructor called (no optional)"
ret% A_list(:) = A_listInput(:)
ret% Feature(:) = ret% B_Feat()
endfunction
p 仍然出现同样的错误
p = B_new()
1
Error: No initializer for component 'a_list' given in the structure constructor at (1)!
这可能是因为没有参数的调用没有匹配的过程(这里我们假设默认结构构造函数需要两个参数)。处理此问题的一种方法可能是使用 optional 关键字,例如
function B_new_Constructor( A_listInput , featInput ) result( ret )
type(A), optional :: A_listInput( 2 )
double precision, optional :: featInput( 2 )
type(B_new) :: ret
print *, "modified constructor called"
if ( present( A_listInput ) ) ret% A_list(:) = A_listInput(:)
if ( present( featInput ) ) then
ret% Feature(:) = featInput(:)
else
ret% Feature(:) = ret% B_Feat()
endif
endfunction
然后程序运行为
modified constructor called
p = 1.24543954074099760E-312 1.24546058728534379E-312 1.24543953672918456E-312 2.12199579096527232E-314 1.22424062937569107E-312 -4.01181304423092194E-321
modified constructor called
q = 1.0 2.0 3.0 4.0 -2.0 2.0 !! format slightly changed to fit the terminal
modified constructor called
r = 1.0 2.0 3.0 4.0 5.0 6.0
此输出表明,给定两个参数,用户定义的构造函数优先于默认结构构造函数。
为了避免optional关键字,我们还可以使用默认初始化器,这样
type A
double precision :: x = 100.0d0, y = 200.0d0
endtype
type, extends(B) :: B_new
type(A) :: A_list(2)
double precision :: Feature(2) = [ 300.0d0, 400.0d0 ]
contains
...
endtype
那么B_new_Constructor()(没有optional)的第一个修改版本也可以工作
p = 100.0 200.0 100.0 200.0 300.0 400.0
modified constructor called (no optional)
q = 1.0 2.0 3.0 4.0 -2.0 2.0
r = 1.0 2.0 3.0 4.0 5.0 6.0
此输出显示至少为 r 调用了默认结构构造函数。
---------
编辑:如果我们只想允许一个参数的构造函数(这里,A_listInput),可能有两种方法。一种是用两个可选参数修改上述B_new_Constructor(),包括以下内容以禁止其他情况:
if ( ( present( A_listInput ) .and. present( featInput ) ) .or. &
( (.not. present( A_listInput )) .and. (.not. present( featInput )) ) ) then
stop "only one arg permitted"
endif
另一种方法是将没有参数或两个参数的构造函数定义为“虚拟”:
function B_new_Constructor_arg1 ( A_listInput ) result( ret )
type(A) :: A_listInput( 2 )
type(B_new) :: ret
ret% A_list(:) = A_listInput(:)
ret% Feature(:) = ret% B_Feat()
endfunction
function B_new_Constructor_arg0 () result( ret )
type(B_new) :: ret
stop "constructor with no argument prohibited"
endfunction
function B_new_Constructor_arg2 ( A_listInput, featInput ) result( ret )
type(A) :: A_listInput( 2 )
double precision :: featInput( 2 )
type(B_new) :: ret
stop "constructor with two arguments prohibited"
endfunction
与
interface B_new
procedure B_new_Constructor_arg1
procedure B_new_Constructor_arg0 !! this masks default initializers (if any)
procedure B_new_Constructor_arg2 !! this masks default structure constructor
endinterface
这两种方法似乎都有效,但都不是很优雅......(希望会有更好的方法来做到这一点)。 [很抱歉,我的回答太长了。]