华为仓颉语言的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.pswp.cn/news/920015.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/920015.shtml
英文地址,请注明出处:http://en.pswp.cn/news/920015.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

健康常识查询系统|基于java和小程序的健康常识查询系统设计与实现(源码+数据库+文档)

健康常识查询系统 目录 基于java和小程序的健康常识查询系统设计与实现 一、前言 二、系统设计 三、系统功能设计 小程序功能设计 后台功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xf…

MySQL的高可用+MHA

即MySQL 主从复制高可用架构&#xff0c;是一套优秀的MySQL 高可用解决方案&#xff0c;由日本 DeNA 公司 youshimaton 开发&#xff0c;主要用于保障 MySQL 数据库在主服务器出现故障时&#xff0c;能快速进行主从切换&#xff0c;减少数据库服务中断时间。其核心特点包括&…

淘宝pc端首页做了哪些性能优化?

淘宝PC端首页作为中国电商领域流量最大的页面之一&#xff0c;其性能优化手段可以说是业界标杆&#xff0c;非常全面和深入。这些优化不是单一技术&#xff0c;而是一个完整的体系。 我们可以从以下几个层面来分析和理解淘宝首页所做的性能优化&#xff1a; 一、核心指标与整体…

让医学数据更直观——MedCalc 23.1.7 最新版使用体验

软件介绍 MedCalc 23.1.7是一款功能强大的生物医学研究统计软件&#xff0c;专为医学科研人员和医疗保健专家设计。它提供了丰富的统计分析工具和方法&#xff0c;旨在帮助用户更好地分析和解释医学数据。以下是该软件的一些主要特点&#xff1a; 一、数据导入和管理 支持导…

Text2SQL、ChatBI简介

概述 传统BI的三大核心瓶颈&#xff1a; 问数之难&#xff1a;不同用户往往存在个性化的分析逻辑&#xff0c;尽管企业内部已经创建大量报表和看板&#xff0c;但仍然无法完全满足业务部门对数据的个性化需求。但传统BI门槛较高&#xff0c;非技术人员在统一培训前&#xff0…

神经网络中 标量求导和向量求导

0. 引出问题 在神经网络反向传播过程中 loss [loss₁,loss₂, loss₃]&#xff0c;为什么 ∂loss/∂w ∂loss₁/∂w ∂loss₂/∂w ∂loss₃/∂w ∂loss₁/∂w 和 loss 维度一样都是三位向量 &#xff0c;[∂loss₁/∂w, ∂loss₂/∂w, ∂loss₃/∂w] 就变成3*3的矩阵 如下所…

tcpdump命令打印抓包信息

tcpdump命令打印抓包信息 下面是在服务器抓取打印服务端7701端口打印 rootgb:/home/gb# ifconfig -a eth0: flags4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 10.250.251.197 netmask 255.255.255.0 broadcast 10.250.251.255inet6 fe80::76fe:48ff:fe94:5a5 …

Mysql-经典实战案例(13):如何通过Federated实现跨实例访问表

实现原理&#xff1a;使用Federated引擎本创建一个链接表实现&#xff0c;但是Federated 引擎只是一个按列的顺序和类型解析远程返回的数据流准备工作&#xff1a; 1. 本地库启用 Federated 引擎查看是否已启用&#xff1a; SHOW ENGINES;如果Federated 引擎的 Support 是 YES …

Linux -- 动静态库

一、什么是库1、动静态库概念# 库是写好的现有的&#xff0c;成熟的&#xff0c;可以复⽤的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个⼈的代码都从零开始&#xff0c;因此库的存在意义⾮同寻常。# 本质上来说库是⼀种可执⾏代码的⼆进制形式&#x…

Linux笔记---单例模式与线程池

1. 单例模式单例模式是一种常用的设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取这个实例。这种模式在需要控制资源访问、管理共享状态或协调系统行为时非常有用。单例模式的核心特点&#xff1a;私有构造函数&#xff1a;防止外部通过n…

Linux中的指令

1.adduseradduser的作用是创立一个新的用户。当我们在命令行中输入1中的指令后&#xff0c;就会弹出2中的命令行&#xff0c;让我们设立新的密码&#xff0c;紧接着就会让我们再次输入新的密码&#xff0c;对于密码的输入它是不会显示出来的&#xff0c;如果输入错误就会让我们…

【n8n】Docker容器中安装ffmpeg

容器化部署 n8n 时&#xff0c;常常会遇到一些环境依赖问题。缺少 docker 命令或无法安装 ffmpeg 是较为常见的场景&#xff0c;如果处理不当&#xff0c;会导致流程执行受限。 本文介绍如何在 n8n 容器中解决 docker 命令不可用和 ffmpeg 安装受限的问题&#xff0c;并给出多…

【基础算法】初识搜索:递归型枚举与回溯剪枝

文章目录一、搜索1. 什么是搜索&#xff1f;2. 遍历 vs 搜索3. 回溯与剪枝二、OJ 练习1. 枚举子集 ⭐(1) 解题思路(2) 代码实现2. 组合型枚举 ⭐(1) 解题思路请添加图片描述(2) 代码实现3. 枚举排列 ⭐(1) 解题思路(2) 代码实现4. 全排列问题 ⭐(1) 解题思路(2) 代码实现一、搜…

Node.js异步编程——async/await实现

一、async/await基础语法 在Node.Js编程中,async关键字用于定义异步函数,这个异步函数执行完会返回一个Promise对象,异步函数的内部可以使用await关键字来暂停当前代码的继续执行,直到Promise操作完成。 在用法上,async关键字主要用于声明一个异步函数,await关键字主要…

搭建一个简单的Agent

准备本案例使用deepseek&#xff0c;登录deepseek官网&#xff0c;登录账号&#xff0c;充值几块钱&#xff0c;然后创建Api key可以创建虚拟环境&#xff0c;python版本最好是3.12&#xff0c;以下是文件目录。test文件夹中&#xff0c;放一些txt文件做测试&#xff0c;main.p…

uv,下一代Python包管理工具

什么是uv uv&#xff08;Universal Virtual&#xff09;是由Astral团队&#xff08;知名Python工具Ruff的开发者&#xff09;推出的下一代Python包管理工具&#xff0c;使用Rust编写。它集成了包管理、虚拟环境、依赖解析、Python版本控制等功能&#xff0c;它聚焦于三个关键点…

单片机的输出模式推挽和开漏如何选择呢?

推挽和开漏是单片机的输出模式&#xff0c;属于I/O口配置的常见类型。开漏&#xff08;Open-Drain&#xff09;和推挽&#xff08;Push-Pull&#xff09;是两种根本不同的输出电路结构&#xff0c;理解它们的区别是正确使用任何单片机&#xff08;包括51和STM32&#xff09;GPI…

java18学习笔记-Simple Web Server

408:Simple Web Server Python、Ruby、PHP、Erlang 和许多其他平台提供从命令行运行的开箱即用服务器。这种现有的替代方案表明了对此类工具的公认需求。 提供一个命令行工具来启动仅提供静态文件的最小web服务器。没有CGI或类似servlet的功能可用。该工具将用于原型设计、即…

深度解析Atlassian 团队协作套件(Jira、Confluence、Loom、Rovo)如何赋能全球分布式团队协作

无穷无尽的聊天记录、混乱不堪的文档、反馈信息分散在各个不同时区……在全球分布式团队中开展真正的高效协作&#xff0c;就像是一场不可能完成的任务。 为什么会这样&#xff1f;因为即使是最聪明的团队&#xff0c;也会遇到类似的障碍&#xff1a; 割裂的工作流&#xff1a…

理解AI 智能体:智能体架构

1. 引言 智能体架构&#xff08;agent architecture&#xff09;是一份蓝图&#xff0c;它定义了AI智能体各组件的组织方式和交互机制&#xff0c;使智能体能够感知环境、进行推理并采取行动。本质上&#xff0c;它就像是智能体的数字大脑——整合了“眼睛”&#xff08;传感器…