第六章派生类型
SEQUENCE 则规定派生类型成员按声明次序存储。
针对上述创建的学生数据类型,
TYPE(Student) student1,student2
声明变量 student1。
TYPE(Student),DIMENSION(100) ::class
声明派生类型数组class。
派生类型的变量声明类似于固有类型,在类型名称前添加 TYPE 关键字, 形式如下:
!电话号码
REAL,DIMENSION(20)
::Marks !各科成绩
END TYPE
构造派生类型的形式为:
TYPE [ [,access] ::] name
component – definition
END TYPE [name]
access代表 PRIVATE 或 PUBLIC 关键字,在模块中定 义数据类型时使用,缺省为 PUBLIC。若规定为 PRIVATE, 则该数据类型只能在模块内使用;
Fortran 95 允许在定义派生类型时,直接给出成员的默认值。如给出成 员 Mark 的默认值为60 :
TYPE Student
CHARACTER(20) NAME
REAL :: Mark = 60
END TYPE
初始化时,成员的默认值将被构造子的表达式列表所覆盖,例如:
TPYE(Student) :: stu1 = Student(“Smith,JR”, 49)
TYPE(Student),INTENT(in)::this
PRINT*,this
END SUBROUTINE
END MODILE
PROGRAM Main
USE Stu_Type
IMPLICIT NONE
TYPE(Student)::stu
CALL Student_(stu,”Smith,JR”)
CALL Student_(stu,“Smith,JR”)
!省略可选参数
CALL Student_(stu,“Smith,JR”,70.0) !传入可选参数
(3)如果派生类型的成员是公有的,可以通过派生类型变量名直接输出其成员 (见例6-1);如果派生类型的成员是私有的,需要设计专门的输出例程(见 例6-2)
!引用定义的派生类型模块
IMPLICIT NONE
TYPE(Student)::stu1=Student(“Smith,JR”,49),stu2
!在声明派生类型变量 stu1 时,用派生类型构造子对其初始化
PRINT*,‘输入stu2的成员:’
READ*,stu2
PRINT*,stu1,stu2,Student(“Bloggs”,50)
CONTAINS
SUBROUTINE Name_From_Student(String,Student)
CHARACTER(*),INTENT(OUT) ::String
TYPE(Student_Type),INTENT(IN) ::Student
String = Student%Name
CALL Print_Student(stu)
END PROGRAM
程序说明:
(1)由于将派生类型的成员声明为私有的,不能在模块外部对其初始化。在程 序中设计了一个类似于 C++ 构造函数的公有例程,以便对其初始化;
(2)使用了可选参数设计构造例程,在初始化时可以灵活决定是否传入可选参 数,例如:
实例6-4:在模块IntegerSets 中定义了一个派生类型 SET (类似于 Pascal 语言中的集合类型),该类型的数据由函数 BuildSet 产生; 定义一个集合关系操作符(.IN.),如果整数 I 是集合 S1 中的成员,那 么表达式 I.IN.S1 返回逻辑真;操作符(*) 被重载,以执行交集操作, 例如,S1*S2 返回集合 S1 和 S2 中共有的数据,假如操作数为固有 数据类型,操作符(*)仍执行乘法运算。
第三节 操作符重载
定义:
假如有某一派生类型的变量 a 和 b,要执行加法运算,我 们自然希望使用“+”运算符,写出表达式 “a+b”,但编 译时会出错,因为编译器不知道该如何完成这个加法操作 (Fortran 90 预定义运算符的运算对象只能是固有数据类 型),这时需要我们自己编写程序说明 “+” 在作用于该派 生类型的变量时,该实现什么样的功能,这就是操作符的 重载,或者是运算符重载。
分类:
Fortran 90 的操作符重载,分为赋值操作符重载和其他操 作符重载。
说明:
操作符重载是对已有的操作符赋予多重含义,使同一操作 符作用于不同类型的数据时产生不同的行为。
1. 赋值操作符重载
将姓名字符串直接赋给派生类型变量,如:
stu = “Smith,JR” !stu 为 Student 派生类型变量
这里的49覆盖了成员 Mark 的默认值60。
说明:如果在模块中定义派生类型时将成员声明为 PRIVATE,则不能
使用构造子进行初始化。例 6-2 所示为派生类型的私有构造
例 6-2 派生类型的私有构造
MODULE Stu_Type
内
IMPLICIT NONE TYPE Student
将数组 class 所有元素的 Female 成员设置为男性。
Student2 = Student1
将 Student1 的所有成员赋给 Student2 的对应成员,同一个派生 类型的2个变量可以相互赋值。
第二节 派生类型的构造及初始化
例6-1,定义一个简单的学生类型,用来说明派生类型的构造
CHARACTER(*),INTENT(in)::n
REAL,OPTIONAL,INTENT(in)::m
this%Name=n
IF(PRESENT(m))THEN
this%Mark=m
ELSE
this%Mark=60
END IF
END SUROUTINE
SUBROUTINE Print_student(this)
从派生类型变量中提取姓名,将派生类型变量直接赋给姓名字 符变量。如:
StuName = stu
! StuName 为字符类型变量
以上操作中需要重新定义赋值操作符,使之可以处理字符类型 和派生类型组成的混合类型。
对第一种情况,需要编写带有两个虚参的子程序例程 (Student_From_Name),两个虚参分别为派生类型和字符 类型,其顺序必须和赋值表达式中出现的顺序相同。在该例 程中,需要显式地将字符参数赋给派生类型的姓名成员;
END PROGRAM !在主程序中使用该派生类型,
派生类型构造子的形式为:
d – name (expr - list)
d – name 指派生类型名;
expr – list 为规定派生类型成员值的表达式列表,表达式的次序、类型、 种类数必须和定义派生类型成员的一致;
派生类型构造子可以出现在初始化中,也可以出现在赋值、输入/输出语 句中。
例6-4 其他操作符重载
MODULE IntegerSets
IMPLICIT NONE
INTEGER, PARAMETER::MaxCard = 100
TYPE SET
PRIVATE
! 规定成员在模块外不可访问
INTEGER Cardinality
INTEGER, DIMENSION(MaxCard)::Members
TYPE(派生类型名) [[,属性] ::] 变量列表
派生类型成员可以和同类型的变量一样使用,但引用派生类型成员时, 须使用成员操作符%,例如:
student1 % Birthdate = 461121
对派生类型变量 student1 的 Birthdate 成员进行赋值。
class % Female = .FALSE.
对第二种情况,是第一种情况的反操作,即子程序例程 (Name_From_Student)的两个虚参分别为字符类型和派生 类型,且将派生类型的姓名成员赋给字符参数。
详见例6-3
例 6-3 赋值操作符重载
MODULE StudentMod
IMPLICIT NONE
TYPE Student_Type
CHARACTER(20)NAME
REAL Mark
END TYPE
INTERFACE ASSIGNMENT(=) !接口块须以 ASSIGNMENT 命名
MODULE PROCEDURE Name_From_Student,
Student_From_Name
END INTERFACE
TYPE Student
CHARACTER(20) Name
!姓名
CHARACTER(10) No
!学号
LOGICAL Female
!性别
INTEGER BirthDate
!出生年月
CHARACTER(20),DIMENSION(4) ::Address !地址
CHARACTER(10) Telephone
第六章 派生类型
固有数据类型,数组集合的元素要求类型相同。 用户定义类型或派生类型,Fortran 90 允许定义不同类型元