第五章 类和对象 示例代码

浙江传媒学院 · 仓颉面向对象程序设计 · 基于 CangStream 框架构建

示例程序
21 个
程序实例
5 个
代码合计
26 个

一、类(5.1)

例5-1 从结构体到类:struct Point 定义

5.1.1:struct Point 含两个 init 构造,展示结构体作为类实现的起点。

package demo

struct Point { 
let x: Int64
let y: Int64
 public init() {
 x=50
 y=100 
}
public init(a:Int64,b:Int64) {
 x=a
 y=b 
} 
}
main(): Int64 {
var a=Point()
var b=Point(5,10)
println(" 点a的坐标为:(${a.x},${a.y})")
println(" 点b的坐标为:(${b.x},${b.y})") 
 return 0
}

例5-2 利用偏旁和部首组字的类

5.1.2:class Hanzi 含 radical/component 两个 String 字段和 compose() 成员函数。

package demo
class Hanzi {
   let radical: String 
   let component: String 
   public init(radical: String, component: String) {
     this.radical = radical
     this.component = component
   }
   public func compose(): String {
     return radical + component
   }
}
// 示例使用
main() {
   let h = Hanzi("氵", "青") // 比如“清”字的组合
   let fullChar = h.compose()
   println("${fullChar}由${h.radical}与${h.component}两部分组成") 
}

二、类的数据成员(5.2)

例5-3 偏旁部首组字类(静态计数器—内联初始化)

5.2.1:static var num=0 内联设置初始值,每次构造自动 num++,Hanzi.num 访问。

package demo

class Hanzi {
   let radical: String 
   let component: String 
   static var num=0
     public Hanzi(radical: String, component: String) {
      this.radical = radical
      this.component = component
     num++
   }
   public func compose(): String {
     return radical + component
   }
}
main() {
   let h1 = Hanzi("氵", "青") 
   let fullChar1 = h1.compose()
   println("第${Hanzi.num}个汉字的组合是:${fullChar1}") 
   let h2 = Hanzi("氵", "王") 
   let fullChar2 = h2.compose()
   println("第${Hanzi.num}个汉字的组合是:${fullChar2}")
}

例5-4 偏旁部首组字类(静态计数器—静态初始化块)

5.2.1:static var num: Int64 不内联赋值,在 static init() 块中显式初始化为 0。

package demo

class Hanzi {
   let radical: String 
   let component: String 
   static var num:Int64
   static init(){
     num=0
   }
    public init(radical: String, component: String) {
     this.radical = radical
     this.component = component
      num++
   }
   public func compose(): String {
     return radical + component
   }
}

例5-5 学生成绩管理类基本框架

5.3:class Student 含 score 属性(get/set 验证范围)和 grade 只读属性(转换成绩等级)。

package demo
class Student {
    var studentId: String=""
    var name: String=""
    var age: Int=0    
    private var internalScore: Float64 = 0.0  
    public mut prop score: Float64 {
        get() {
            return internalScore
        }
        set(value) {
            if (value >= 0.0 && value <= 100.0) {
                internalScore = value
            }
        }
    }
    public prop grade: String {
        get() {
            if (this.score >= 90.0) {return "A"}
            if (this.score >= 80.0) {return "B"}
            if (this.score >= 70.0) {return "C"}
            if (this.score >= 60.0) {return "D"}
            return "还没有录入成绩!"
        }
    }
}
main() {
    let stdent = Student()
    println(stdent.grade)
}

三、类的构造函数(5.3)

例5-6 Hanzi 类三重构造函数重载

5.3.1:普通构造函数重载,分别支持零参、单参(偏旁=部首)、双参三种创建方式。

package demo
class Hanzi {
   let radical: String  
   let component: String 
   static var num=0 
   public init(){
     this.radical="氵" 
     this.component="永"
     num++ 
     } 
   public init(radical: String){
     this.radical=radical 
     this.component=radical
    num++
     } 
   public init(radical: String, component: String) {
     this.radical = radical
     this.component = component
       num++
      }
   public func compose(): String {
     return radical + component
   }
}
main() {
   let h1 =Hanzi() 
   let fullChar1 = h1.compose()
   println("第${Hanzi.num}个汉字的组合是:${fullChar1}") 
   let h2 = Hanzi("木") 
   let fullChar2 = h2.compose()
   println("第${Hanzi.num}个汉字的组合是:${fullChar2}")
    let h3 = Hanzi("氵","木") 
   let fullChar3 = h3.compose()
   println("第${Hanzi.num}个汉字的组合是:${fullChar3}")
}

例5-7 Student 主构造函数版本

5.3.2:Student(var studentId, var name, var age, var internalScore) 主构造函数语法,字段与参数同名自动绑定。

package demo

class Student {
     Student(var studentId: String,var name: String,var age: Int,var internalScore: Float64){
        this.studentId=studentId
        this.name=name
        this.age=age
        this.internalScore=internalScore
    }
    public mut prop score: Float64 {
        get() {
            return internalScore
        }
        set(value) {
            if (value >= 0.0 && value <= 100.0) {
                internalScore = value
            }
        }
    }
    public prop grade: String {
        get() {
            if (this.score >= 90.0) {return "A"}
            if (this.score >= 80.0) {return "B"}
            if (this.score >= 70.0) {return "C"}
            if (this.score >= 60.0) {return "D"}
            return "还没有录入成绩!"
        }
    }
}
main() {
    let student = Student("250101","李晓泓",25,90.6)
    println(student.grade)
}



例5-8 Time 类(普通构造函数 + 主构造函数)

5.3.2:同时定义 init()(无参)和 Time(h, m, s)(主构造),演示两者共存与调用。

package demo
class Time {
   private var hour: Int64
   private var minute: Int64
   private var second: Int64
    // 普通构造器
  public init() {
     this.hour = 0
     this.minute = 0
     this.second =0
   }
    // 主构造器
   public Time(h: Int64, m: Int64, s: Int64) {
     this.hour = h
     this.minute = m
     this.second = s
   }
   // 设置时间
   public func setTime(h: Int64, m: Int64, s: Int64): Unit {
     this.hour = h
     this.minute = m
     this.second = s
   }
   // 显示时间
   public func showTime(): Unit {
     println("${hour}.${minute}.${second}")
   }
}

main(): Int64 {
   var t = Time()  //调用普通构造器
   println("初始时间:")
   t.showTime()
   println("第一次更新后的时间:")
   t=Time(8, 15, 0)
   t.showTime()
   println("第二次更新后的时间:")
   t.setTime(14, 5, 0)
   t.showTime()
   return 0
}

例5-9 Time 类(仅主构造函数简化版)

5.3.2:仅保留 Time(var hour, var minute, var second){},体现主构造函数的最简形式。

package demo
class Time {
    public Time( var hour: Int64, var minute: Int64, var second: Int64) {}
    public func setTime(h: Int64, m: Int64, s: Int64): Unit {
        this.hour = h
        this.minute = m
        this.second = s
    }
    // 显示时间
    public func showTime(): Unit {
        println("${hour}.${minute}.${second}")
    }
}

main(): Int64 {
   var t = Time(0, 0, 0)  //调用主构造器(初始化为零时刻)
   println("初始时间:")
   t.showTime()
   println("第一次更新后的时间:")
   t=Time(8, 15, 0)
   t.showTime()
   println("第二次更新后的时间:")
   t.setTime(14, 5, 0)
   t.showTime()
   return 0
}

四、类的成员函数(5.4)

例5-10 汉字的分解与显示(示例成员函数)

5.4.1:Hanzi 含 character/radical/component 三字段,display() 格式化输出组合关系。

package demo
class Hanzi{
      Hanzi(var character :String,var radical: String, var component: String){
        this.character=character
        this.radical=radical
        this.component=component
            }
    public func display() {
       println("${character}=${radical}+${component}")
    }
}
main() {
    let h1 =Hanzi("清","氵","青") 
    let h2 =Hanzi("江","氵","工") 
    let h3 =Hanzi("汪","氵","王")
    let hanziList: Array<Hanzi> = [h1, h2, h3]
    for (h in hanziList) {
        h.display()
    }   
}

例5-11 静态成员函数 typeName

5.4.2:public static func typeName() 只能通过类名调用,不能访问实例字段。

package demo

class Hanzi {
    public Hanzi(var radical: String, var component: String ){} 
    static var num=0
    public init(){
       this.radical="氵" 
       this.component="永"
       num++ 
      } 
    public static func typeName(): String { "泳" }
    public func compose(): String {
       return typeName()+"="+radical +"+"+ component
    }
}
main() {
    let h1 = Hanzi() 
    println("第${Hanzi.num}个:${h1.compose()}") 
}

例5-12 Point 类 setPoint/getx/gety 成员函数

5.4.1:private var x/y 隐藏实现细节,通过 setPoint、getx、gety 提供受控访问。

package demo

class Point {
    private var x: Int64 = 0
    private var y: Int64 = 0
    // 设置点的坐标
    public func setPoint(a: Int64, b: Int64): Unit {
       this.x = a
       this.y = b
    }
    // 获取x坐标
    public func getx(): Int64 {
       return this.x
       }
       // 获取y坐标
       public func gety(): Int64 {
       return this.y
    }
}
main(): Int64 {
    // 创建一个Point对象
    let obja = Point()
    // 调用setPoint初始化坐标
    obja.setPoint(100, 200)
      // 读取坐标并输出
    let i = obja.getx()
    let j = obja.gety()
    println("obja i=${i} obja j=${j}")
    return 0
}

五、函数和操作符重载(5.5)/ 类的终结器(5.6)

例5-13 Circle 类终结器 ~init()

5.6:构造时 mallocCString 分配 CString 资源,~init() 终结器自动释放,演示 RAII 模式。

package demo
class Circle {
    var name: CString   // 圆的名称
    let radius: Float64
    // 构造函数:分配CString资源
    public init(r: Float64, label: String) {
        radius = r
        name = unsafe { LibC.mallocCString(label) }
        println("创建圆:${label},半径=${r}")
    }
    // 终结器:释放系统资源
    ~init() {
        unsafe { LibC.free(name) }
        println("释放圆的资源")
    }
    // 计算面积
    public func area(): Float64 {
        3.14* radius * radius
    }
}
main() {
        let c = Circle(5.0, "单位圆")
        println("面积=${c.area()}")        
     // 块结束,c 被销毁,此时自动调用 ~init()
}

六、类成员及访问(5.7)

例5-14 访问运算符:Point setPoint/getx/gety

5.7.1:用 . 运算符调用成员函数,演示通过公有方法访问私有字段的封装模式。

package demo
class Point {
    private var x: Int64 = 0
    private var y: Int64 = 0
    // 设置点的坐标
    public func setPoint(a: Int64, b: Int64): Unit {
        this.x = a
        this.y = b
    }
    // 获取x坐标
    public func getx(): Int64 {
        return this.x
    }
    // 获取y坐标
    public func gety(): Int64 {
        return this.y
    }
}
main(): Int64 {
    // 创建一个Point对象
    let obja = Point()
    // 调用setPoint初始化坐标
    obja.setPoint(100, 200)
     // 读取坐标并输出
    let i = obja.getx()
    let j = obja.gety()
    println("obja i=${i} obja j=${j}")
    return 0
}








例5-15 访问属性:Data 类三种修饰符

5.7.3:private var x、protected var y、public var z 三种访问级别,展示可见性差异。

package demo

class Data {
    private var x: Int64 = 0    // 私有变量
    protected var y: Int64 = 0  // 受保护变量
    public var z: Int64 = 0     // 公有变量

    // 公有函数:设置数据
    public func setData(a: Int64, b: Int64, c: Int64): Unit {
        this.x = a
        this.y = b
        this.z = c
    }

    // 公有访问器函数
    public func getx(): Int64 {
        return this.x
    }

    public func gety(): Int64 {
        return this.y
    }

    public func getz(): Int64 {
        return this.z
    }
}

main(): Int64 {
    let obj = Data()
    obj.setData(1, 2, 3)

    println("obj.x=${obj.getx()}") // 通过公有函数访问私有成员
    println("obj.y=${obj.gety()}") // 通过公有函数访问受保护成员
    println("obj.z=${obj.z}")      // 直接访问公有成员

    return 0
}

七、对象(5.8)

例5-16 创建对象(Point 含静态计数器)

5.8.1:Point 带静态计数器 n,构造时递增,展示点的坐标和两点之间的欧氏距离。

package demo
import std.math.*
class Point { 
    let x: Int64
    let y: Int64
    static var n=0
    init(x: Int64, y: Int64) {
        this.x = x
        this.y = y  
        n++      
    }
     func distance(topoint: Point):Float64 {
        let dx=Float64(x - topoint.x) 
        let dy=Float64( y - topoint.y)
        return Float64(sqrt(dx*dx+dy*dy))  // 计算两点间的欧氏距离        
    }  
}
main(): Int64 {
    let a =Point(10,20)      
    println(" 第${Point.n}个点的坐标是:(${a.x},${a.y})")
    var b =Point(100,200)
    println(" 第${Point.n}个点的坐标是:(${b.x},${b.y})")
    let dis=Int64(a.distance(b))
    println(" 两点之间的距离是:(${dis})") 
    return 0
}

例5-17 创建对象数组(Point 数组)

5.8.2:用 Array[Point] 保存多个点对象,含默认构造和带参构造,计算两点距离。

package demo
import std.math.*
class Point {
    static var n: Int64 =0  // 静态变量:记录点的个数
    var x: Float64
    var y: Float64
    public init() {
        this.x = 0.0
        this.y = 0.0
       }
    public init(x: Float64, y: Float64) {
        this.x = x
        this.y = y
        Point.n++
    }
    // 成员函数:计算与另一点之间的距离
    public func distance(p: Point): Float64 {
        let dx = this.x - p.x
        let dy = this.y - p.y
        return sqrt(dx * dx + dy * dy)
    }
}
// 主函数
main(): Int64 {
    // 用(0,0)作为第一个默认点,创建一个点数组,初始有两个点
    var pts: Array<Point> = [ Point(10.0, 20.0), Point() ]
    println("默认点的坐标是:(${Int64(pts[1].x)},${Int64(pts[1].y)})")
    println("第${Point.n}个点的坐标:(${Int64(pts[0].x)},${Int64(pts[0].y)})")    
    // 计算两点之间的距离
    var dis = pts[0].distance(pts[1])
    println("两点之间的距离是:${Int64(dis)}")
    return 0
}

例5-18 对象数据成员(Point + Line 组合)

5.8.3:class Line 以两个 Point 对象为成员,length() 调用 Point.distance() 计算线段长度。

package demo
import std.math.*
// 点类定义
class Point {
    var x: Int64
    var y: Int64
    public init(x: Int64, y: Int64) {
        this.x = x
        this.y = y
    }
    public func print() {
        println("(${x}, ${y})")
    }
     func distance(topoint: Point):Float64 {
        let dx=Float64(x - topoint.x) 
        let dy=Float64( y - topoint.y)
        return (sqrt(dx*dx+dy*dy))  // 计算两点间的欧几里得距离        
    }  
}
// 直线类,包含两个点
class Line {
    var start: Point
    var end: Point
    public init(start: Point, end: Point) {
        this.start = start
        this.end = end
    }
    // 打印起点和终点
    public func print() {
        print("直线起点:")
        start.print()
        print("直线终点:")
        end.print()
    }
    // 计算线段长度
    public func length(): Float64 {
        return start.distance(end)
    }
}
main(): Int64 {
    // 创建两个点对象
    let p1 = Point(1, 2)
    let p2 = Point(4, 6)
    // 使用点对象构建直线对象
    let line = Line(p1, p2)
    // 打印直线信息
    line.print()
    // 输出线段长度
    let len = line.length()
    println("直线长度为:${len}")
    return 0
}

例5-19 对象赋值语句(引用复制语义)

5.8.4:obj2 = obj1 使两个变量指向同一对象,修改任一方向对方的字段同步改变。

package demo

class Point {
    private var x: Int64 = 0
    private var y: Int64 = 0

    // 设置点坐标
    public func setPoint(a: Int64, b: Int64): Unit {
        this.x = a
        this.y = b
    }

    // 显示坐标
    public func show(): Unit {
        println("${x} ${y}")
    }
}

main(): Int64 {
    var obj1 = Point()
    var obj2 = Point()

    obj1.setPoint(1, 2)
    obj2 = obj1  // 对象赋值(引用复制)

    obj1.show()
    obj2.show()

    return 0
}

八、类的作用域与自引用指针(5.9)

例5-20 类的作用域(Abc 类)

5.9.1:成员函数内的 x 直接引用本类成员变量,无需 this;外部通过实例名访问。

package demo
class Abc {
    public var x: Int64 = 0
    // 设置成员变量 x
    public func set(a: Int64): Unit {
        this.x = a
    }
    // 显示 x
    public func show(): Unit {
        println("x=${x}")
    }
}
main(): Int64 {
    let obj = Abc()
    obj.set(2)
    obj.show()
    obj.x = 3
    obj.show()
    return 0
}

例5-21 自引用指针 this(Finger 类)

5.9.2:this 指针指向当前对象,static counter 记录创建顺序,this.id 存储唯一编号。

package demo
class Finger {
    private var x: Int64
    private var id: Int64  // 模拟唯一标识(this 指针)
    // 静态计数器
    static var counter: Int64 = 0
    // 构造函数
    public init(x1: Int64) {
        this.x = x1
        Finger.counter++
        this.id = Finger.counter
    }
    public func disp(): Unit {
        println("this=对象${id} when x=${x}")
    }
}
main(): Int64 {
    let a = Finger(1)
    let b = Finger(2)
    let c = Finger(3)
    a.disp()
    b.disp()
    c.disp()
    return 0
    }

九、程序实例(5.10)

实例1 汉字类及生成计数器设计

Hanzi 类封装偏旁/部首(private),static totalCount 统计总数,getInfo() 格式化输出组合信息。

package demo
class Hanzi {
    private let radical: String     // 使用private访问控制,提高封装性
    private let component: String       
    static var totalCount: Int64 = 0    // 静态变量用于统计汉字总数
    public init(radical: String, component: String) { // 构造函数
        this.radical = radical
        this.component = component
        Hanzi.totalCount++
    }    
       public func compose(): String {//  组合汉字方法
        return "${radical}${component}"
    }       
    public func getRadical(): String {// 获取偏旁
        return radical
    }       
    public func getComponent(): String {// 获取部首
        return component
    }     
    public static func getTotalCount(): Int64 {  // 静态方法获取总数
        return totalCount
    }    
    public static func resetCount(): Unit { // 重置计数器(重新开始统计)
        totalCount = 0
    }       
    public func getInfo(): String {// 获取汉字信息的详细描述
        return "偏旁「${radical}」+ 部首「${component}」→ 汉字「${compose()}」"
    }
}
main() {
    let h1 = Hanzi("氵", "青")
    let h2 = Hanzi("亻", "言")
    let h3 = Hanzi("口", "马")
    println("组合的汉字有:")
    println(h1.getInfo())
    println(h2.getInfo())
    println(h3.getInfo())
    println("共组合了${Hanzi.totalCount}个汉字")
}

实例2 用对象作为成员确定类与类的关系

Point(坐标+距离)作为 Line 的成员,line.print() 输出起终点,line.length() 计算线段长度。

package demo
import std.math.*
// 点类定义
class Point {
    public let x: Int64
    public let y: Int64
    public init(x: Int64, y: Int64) {
        this.x = x
        this.y = y
    }
    public func print() {
        println("(${x}, ${y})")
    }
    func distance(topoint: Point): Float64 {
        let dx = Float64(x - topoint.x)
        let dy = Float64(y - topoint.y)
        return sqrt(dx*dx + dy*dy)
    }
}
// 直线类,包含两个点
class Line {
    var start: Point
    var end: Point
    public init(start: Point, end: Point) {
        this.start = start
        this.end = end
    }
    // 打印起点和终点
    public func print() {
        print("直线起点:")
        start.print()
        print("直线终点:")
        end.print()
    }
    // 计算线段长度
    public func length(): Float64 {
        return start.distance(end)
    }
}
main(): Int64 {
    let p1 = Point(0, 0)
    let p2 = Point(3, 4)
    let line = Line(p1, p2)
    line.print()
    let len = line.length()
    println("直线长度为:${len}")
    return 0
}

实例3 使用对象数据管理点集并计算距离

Array[Point] 管理点集,循环输出各点坐标及相邻两点距离,综合展示对象数组的使用。

package demo

import std.math.*
class Point {
    public let x: Float64
    public let y: Float64    
    public init(x: Float64, y: Float64) {
        this.x = x
        this.y = y    }     
    public init(x: Int64, y: Int64) {
        this.x = Float64(x)
        this.y = Float64(y)
    }    
    // 计算到另一点的距离
    public func distanceTo(other: Point): Float64 {
        let dx = this.x - other.x
        let dy = this.y - other.y
        return sqrt(dx * dx + dy * dy)
    }
    public func toString(): String {
        return "(${Int64(x)}, ${Int64(y)})"
    }    
}
main() {
    let pts: Array<Point> = [ Point(1, 2), Point(3, 4), Point(5, 6) ]
    for (i in 0..pts.size-1) {
       print("第${i+1}个点的坐标:")
       println("${pts[i].toString()}")       
       println("第${i+1}个点与第${i+2}个点的距离是:${pts[i].distanceTo(pts[i+1])}")    
     } 
      print("第${pts.size}个点的坐标:")
      println("${pts[pts.size-1].toString()}")    
} 

实例4 时间类 Time 设计

Time 类含 hour/minute/second 三字段,show() 展示当前时间,setTime() 修改时间值。

package demo

class Time {
    var hour: Int64
    var minute: Int64
    var second: Int64
    public init(h: Int64, m: Int64, s: Int64) {
        this.hour = h
        this.minute = m
        this.second = s
    }
    public func show(): Unit {
        println("时间是:${hour}:${minute}:${second}")
    }
    public func setTime(h: Int64, m: Int64, s: Int64): Unit {
        this.hour = h
        this.minute = m
        this.second = s
    }
}
main(): Int64 {
    let t = Time(8, 30, 0)
    t.show()
    t.setTime(14, 45, 30)
    t.show()
    return 0
}

实例5 利用枚举和类确定笛卡儿坐标系中点的位置属性

enum Quadrant 定义七种位置(四象限/原点/X轴/Y轴),Point.getInfo() 用 match 给出点的坐标与位置描述。

package demo
// 枚举定义象限
enum Quadrant {
    | First      // 第一象限 (+,+)
    | Second     // 第二象限 (-,+)  
    | Third      // 第三象限 (-,-)
    | Fourth     // 第四象限 (+,-)
    | Origin     // 原点
    | XAxis      // X轴
    | YAxis      // Y轴
}
class Point {
    public let x: Float64
    public let y: Float64    
    public init(x: Float64, y: Float64) {
        this.x = x
        this.y = y    }     
    public init(x: Int64, y: Int64) {
        this.x = Float64(x)
        this.y = Float64(y)
    }    
   
     // 判断点所在象限
    public func getQuadrant(): Quadrant {
        if (x == 0.0 && y == 0.0) { return Quadrant.Origin }
        if (x == 0.0) { return Quadrant.YAxis }
        if (y == 0.0) { return Quadrant.XAxis }
        if (x > 0.0 && y > 0.0) { return Quadrant.First }
        if (x < 0.0 && y > 0.0) { return Quadrant.Second }
        if (x < 0.0 && y < 0.0) { return Quadrant.Third }
        return Quadrant.Fourth
    }
    public func toString(): String {
        return "(${Int64(x)}, ${Int64(y)})"
    }  
    // 获取点的详细信息
    public func getInfo(): String {
        let quadrant = match (getQuadrant()) {
            case Quadrant.Origin => "原点"
            case Quadrant.First => "第一象限"
            case Quadrant.Second => "第二象限"
            case Quadrant.Third => "第三象限"
            case Quadrant.Fourth => "第四象限"
            case Quadrant.XAxis => "X轴"
            case Quadrant.YAxis => "Y轴"
        }
        return "${toString()}, 位于:${quadrant}"
    }  
}
main() {
    let pts: Array<Point> = [ Point(1, 2), Point(-3, 4), Point(0, -6) ]
    for (i in 0..pts.size) {
       print("第${i+1}个点的坐标是")
       println("${pts[i].getInfo()}")     
     }     
}