当前位置: 首页 > news >正文

华为仓颉语言的class(类)初步

华为仓颉语言的class(类)初步

class 概念

【官方文档 https://cangjie-lang.cn/docs?url=%2F1.0.0%2Fuser_manual%2Fsource_zh_cn%2Fclass_and_interface%2Fclass.html 】

class 是仓颉面向对象体系的核心,用来描述“引用类型”对象。与 struct(值类型)相比,class 实例在赋值、传参时是引用语义,并天然支持继承与多态 。注意:class 只能定义在源文件的顶层作用域。

class 类型的定义以关键字 class 开头,后跟 class 的名字,接着是定义在一对花括号中的 class 定义体。class 定义体中可以定义一系列的成员变量(member variables)、成员属性(member properties)、静态初始化器(static initializers)、构造函数(constructors)、成员函数(member functions)和操作符函数(operator functions)。

一个类的基本定义语法如下:

class 类名 {

    // 成员变量

    // 构造函数

    // 成员函数

    // 成员属性

}

说明:

类名通常推荐采用帕斯卡命名法(首字母大写,如 Person、Car)。

类体中可包含成员变量、成员方法、构造函数、成员属性等,用于描述类的特征数据和行为。

成员属性:提供了对成员变量更灵活和安全的访问方式,可以包含自定义的 getter 和 setter。

【关于Property(属性)的说明

在仓颉语言(Cangjie)的官方文档中,统一使用 Property 来表示“属性”。

属性(Properties)提供了一个 getter 和一个可选的 setter 来间接获取和设置值。

仓颉语言的class 定义体中

数据成员变量不像有些语言那样称为attribute。

成员属性就是指属性(Properties)。

术语

英文

定义

属性

Property

通过getter/setter间接访问的成员,提供计算、验证等逻辑

成员变量

Member Variable

直接存储数据的普通字段(无getter/setter)

attribute

❌ 非官方术语

在仓颉中不适用(其他语言如Python的术语)

例如:


class Rectangle {
    // 成员变量
    let width: Int64
    let height: Int64

    // 构造函数
    public init(width: Int64, height: Int64) {
        this.width = width
        this.height = height
    }

    // 成员函数
    public func area(): Int64 {
        return width * height
    }
}

创建对象

语法

let/var 变量名[: 类型] = 类型名(构造函数参数)

通常[: 类型]部分可省略,由编译器自动推断

示例:简单类的定义及对象创建示例

// 定义一个简单的 Person 类
class Person {var name: Stringvar age: Int64// 构造函数public init(name: String, age: Int64) {this.name = namethis.age = age}public func introduce(): Unit {println("Hello, my name is ${name} and I am ${age} years old.")}
}// 在 main 函数或其他方法中创建对象
main() {// 1. 使用 var 声明,可以改变引用指向的对象var person1 = Person("Alice", 30) // 调用 init(name, age) , 等号前也可写为var person1: Person =person1.introduce() // 输出: Hello, my name is Alice and I am 30 years old.// person1 引用可以重新赋值,指向一个新的 Person 对象person1 = Person("Bob", 25)person1.introduce() // 输出: Hello, my name is Bob and I am 25 years old.// 2. 使用 let 声明,引用不可变let person2 = Person("Charlie", 40)person2.introduce() // 输出: Hello, my name is Charlie and I am 40 years old.// 下面这行代码会编译错误,因为 person2 是不可变引用// person2 = Person("David", 35)// 但是,对象内部的成员变量如果是 var,仍然可以通过引用修改person2.age = 41 // 这是允许的,因为 person2.age 是 varperson2.introduce() // 输出: Hello, my name is Charlie and I am 41 years old.    
}

编译运行截图:

仓颉class 几点说明

• 成员变量写在类体;可追加 public / private / protected 等可见性修饰符(缺省为 internal)。

【访问控制修饰符:

private 私有,表示在 class 定义内可见。

internal 内部,表示仅当前包及子包(包括子包的子包,详见包)内可见。缺省。

protected 受保护,表示当前模块(详见包)及当前类的子类可见。

public 公开,表示模块内外均可见。】

• 仓颉class 支持两类构造函数,规则与初始化顺序全部与 struct 一致 :

普通构造函数:名字固定为 init,可重载。

主构造函数:名字与类名相同,最多一个,可把形参同时声明为成员变量。

一个 类可以有多个构造函数。

例如:

class Person {
    var name: String
    var age: Int64

    // 主构造函数
    public init(name: String, age: Int64) {
        this.name = name
        this.age = age
    }

    // 辅助构造函数,调用主构造
    public init(name: String) {
        this.init(name, 0) // 调用主构造函数
    }
}

初始化顺序:

① 先初始化主构造之外、带缺省值的变量;

② 如果构造函数体内未显式调用父类构造函数或本类其他构造函数,则调用父类的无参构造函数 super(),如果父类没有无参构造函数,则报错;

③ 执行构造函数体。

示例

open class Parent {var a: Int64 = 1 // 步骤1.1:父类字段初始化var b: Int64// 父类主构造函数public init(b: Int64) {// 步骤3.1:执行父类构造函数体this.b = bprintln("Parent constructor body")}
}class Child <: Parent {var x: Int64 = 3 // 步骤1.2:子类字段初始化var y: Int64// 子类主构造函数public init(b: Int64, y: Int64) {// 隐式或显式调用父类构造函数!这是步骤2super(b) // 步骤2:调用父类构造函数// 步骤3.2:执行子类构造函数体this.y = yprintln("Child constructor body")}
}main() {// 创建实例时: let obj = Child(2, 4)
}

输出:

Parent constructor body
Child constructor body

发生的顺序实际上是:

1.Parent.a 被赋值为 1

2.Child.x 被赋值为 3

3.开始执行 Child.init 中的代码:

    a. 首先调用 super(b),即 Parent.init(b)。

    b. 执行 Parent.init:

        - Parent.b 被赋值为 2 (来自参数)。

        - 打印 "Parent constructor body"。

    c. Parent.init 执行完毕,返回。

4.继续执行 Child.init 的剩余部分:

    a. Child.y 被赋值为 4。

    b. 打印 "Child constructor body"。

示例:父类没有无参构造,子类忘记显式 super → 编译错误

open class Parent {var b: Int64public init(b: Int64) {this.b = bprintln("Parent body")   } // 只有这一个构造函数
}class Child <: Parent {public init() {super(0) // 注意:若无此行,编译报错!println("Child body")}
}main() {// 创建实例时: let obj = Child()
}

属性(Property

仓颉的属性(Property)提供了对类内部状态的受控访问,它可以包含 getter 和 setter。

示例:

class Person {private var _age: Int64 = 0// 1) 可读写属性:带 mut,可在 set 中拦截或记录public mut prop age: Int64 {get() {println("getter: 读取 _age")_age}set(value) {println("setter: 写入 _age = ${value}")_age = value}}// 2) 只读计算属性:没有 setter,始终根据 _age 计算public prop isAdult: Bool {get() {_age >= 18}}
}// ---------------- 演示 ----------------
main(): Int64 {let p = Person()println("--- 写属性 ---")p.age = 15        // 触发 setterprintln("--- 读属性 ---")let a = p.age     // 触发 getterprintln("读取到的 age = ${a}")println("--- 只读属性 ---")println("isAdult = ${p.isAdult}")   // 15 < 18 → falsep.age = 20        // 再次触发 setterprintln("isAdult = ${p.isAdult}")   // 20 ≥ 18 → true0 // return 0
}

输出:

--- 写属性 ---
setter: 写入 _age = 15
--- 读属性 ---        
getter: 读取 _age     
读取到的 age = 15     
--- 只读属性 ---      
isAdult = false
setter: 写入 _age = 20
isAdult = true

抽象类(abstract class

抽象类使用 abstract 修饰,不能实例化的类,用于定义子类的共同接口,可包含抽象方法(无实现)和具体方法(有实现),子类必须实现抽象方法。

抽象类定义时的 open 修饰符是可选的——抽象类默认可继承(无需open)。

注意:

  •  抽象类中禁止定义 private 的抽象函数;

  •  不能为抽象类创建实例;

  •  抽象类的非抽象子类必须实现父类中的所有抽象函数。

抽象类还可以被 sealed 修饰,表示该抽象类只能在其定义所在的包内被其他类继承。

示例1:

// 1. 抽象类定义,本身就隐含 open,无需再写
abstract class Shape {// 抽象方法:public func getArea(): Float64// 具体方法:实现写在方法体里public func printArea(): Unit {println("面积:${this.getArea()}")}
}// 2. 子类
class Circle <: Shape {let radius: Float64            // 成员变量用 let/var 声明// 构造函数:仓颉只有 init,没有 constructorpublic init(radius: Float64) {super()                    // 调用父类构造函数this.radius = radius}// 实现抽象方法public override func getArea(): Float64 {3.1415926 * radius * radius}
}// 3. 创建对象
main() {let circle: Shape = Circle(2.0)circle.printArea()             // 输出:面积:12.5663704   
}

示例 2:

// 1. 抽象类定义,本身就隐含 open,无需再写
abstract class AbstractBase {// 抽象方法:public func doSomething(): Unit
}// 2. 同包下的实现类
class Concrete <: AbstractBase {// 实现抽象方法public override func doSomething(): Unit {println("实现抽象方法")}
}// 3. 密封抽象类:仅本包可继承
sealed abstract class SealedAbstract {public func baseFunc(): Unit {}      // 具体方法
}// 4. 同包子类继承密封抽象类——合法
class SamePackageChild <: SealedAbstract {}// 6. 演示 main
main() {let obj1: AbstractBase = Concrete()obj1.doSomething()          // 输出:实现抽象方法let obj2 = SamePackageChild()obj2.baseFunc()             // 无输出,仅演示可实例化  
}

class是引用类型

华为仓颉语言的class是引用类型,定义为引用类型的变量,变量名中存储的是指向数据值的引用,因此在进行赋值或函数传参等操作时,拷贝的是引用。

示例

class MyClass {var value: Int64 = 0
}main(): Int64 {let a = MyClass() // a 是一个引用,指向新创建的 MyClass 对象a.value = 10let b = a         // 将 a 的引用拷贝给 b。现在 a 和 b 指向同一个对象!b.value = 20      // 通过 b 修改对象println(a.value)  // 输出 20,因为 a 指向的对象已被修改return 0
}

继承 / 实现 / 多态要点

• 单继承:用 <: 符号,如 class Student <: Person { ... } 。

• 父类必须被 open 修饰才能被继承。

• 方法重写:子类方法前加 override;如果一个方法没有 open 修饰,则子类不能重写它。

【注意,“方法重写(override)”只是实现运行时多态的一种技术手段;多态(Polymorphism)本身是一个更宽泛的概念。】

示例:

// 1. 父类定义:// 类必须用 open 才能被继承,默认实现返回 0
open class Shape {public open func area(): Float64 {         // 用 open 声明可重写0.0}func show() {                       // 非 open,子类不能重写println("面积 = ${this.area()}")}
}// 2. 子类 Circle:重写 area()
class Circle <: Shape {let r: Float64init(r: Float64) {super()this.r = r}public override func area(): Float64 {     // 必须写 override3.1415926 * r * r}
}// 3. 子类 Rectangle:再次重写 area()
class Rectangle <: Shape {let w: Float64let h: Float64init(w: Float64, h: Float64) {super()this.w = wthis.h = h}public override func area(): Float64 {w * h}
}// 4. 演示多态
main(): Int64 {let shapes: Array<Shape> = [Circle(2.0), Rectangle(3.0, 4.0)]for (s in shapes) {s.show()     // 运行时根据实际对象调用对应 override}0 return 0
}

输出:

面积 = 12.566370
面积 = 12.000000

http://www.lryc.cn/news/626950.html

相关文章:

  • 比剪映更轻量!SolveigMM 视频无损剪切实战体验
  • 将集合拆分成若干个batch,并将batch存于新的集合
  • ubuntu下安装vivado2015.2时报错解决方法
  • 换根DP(P3478 [POI 2008] STA-StationP3574 [POI 2014] FAR-FarmCraft)
  • Qt 中最经典、最常用的多线程通信场景
  • 通过自动化本地计算磁盘与块存储卷加密保护数据安全
  • 链表-24.两两交换链表中的结点-力扣(LeetCode)
  • ansible playbook 实战案例roles | 实现基于firewalld添加端口
  • SSM从入门到实战:2.1 MyBatis框架概述与环境搭建
  • 【LeetCode 热题 100】279. 完全平方数——(解法三)空间优化
  • innovus auto_fix_short.tcl
  • 代码随想录Day57:图论(寻宝prim算法精讲kruskal算法精讲)
  • 3D检测笔记:相机模型与坐标变换
  • 今日行情明日机会——20250820
  • 算法提升树形数据结构-(线段树)
  • 数据结构与算法系列(大白话模式)小学生起点(一)
  • 关于 Flask 3.0+的 框架的一些复习差异点
  • 算法230. 二叉搜索树中第 K 小的元素
  • 雷卯针对香橙派Orange Pi 5B开发板防雷防静电方案
  • 力扣hot100:最大子数组和的两种高效方法:前缀和与Kadane算法(53)
  • Deepseek+python自动生成禅道测试用例
  • 自动化测试用例生成:基于Python的参数化测试框架设计与实现
  • 记一次pnpm start启动异常
  • Spring Boot 3整合Nacos,配置namespace
  • 质谱数据分析环节体系整理
  • Rust 入门 包 (二十一)
  • 内网环境给VSCode安装插件
  • PostgreSQL 流程---更新
  • 基于51单片机自动浇花1602液晶显示设计
  • Notepad++批量转UTF-8脚本