仓颉编程语言入门 -- 类的介绍

在面向对象编程的语境下,class 是构建对象的基石,而 struct 虽然在某些语言中扮演着类似角色,但它们在类型处理上有所不同。class 被归类为引用类型,意味着当它们被赋值或作为参数传递时,实际上传递的是对对象实例的引用,而非对象本身。相比之下,struct 则是值类型,其赋值和传递操作会复制整个结构体的内容。

定义一个 class 类型始于 class 关键字,后接类名,类体则包含在一对花括号内。在这个类体中,可以声明成员变量、属性(封装了字段的访问方式)、构造函数(用于初始化对象)、成员函数以及可能的操作符重载方法。此外,class 支持继承机制,允许一个类继承另一个类的属性和方法,而 struct 在大多数语言中则不支持继承。

一. class的定义

具体到实现上,我们首先定义一个 class,然后可以通过 new 关键字创建该类的实例(即对象)。对象创建后,可以访问其公有成员(包括属性和方法),并进行相应的操作。如果类之间存在继承关系,子类可以重写继承自父类的虚方法,或者添加新的成员和方法。这种继承机制促进了代码的复用和扩展性。

简而言之,classstruct 在面向对象编程中各有其用,但 class 由于其支持引用传递和继承的特性,在构建复杂系统时更为常用。

class Rectangle {
    let width: Int64
    let height: Int64

    public init(width: Int64, height: Int64) {
        this.width = width
        this.height = height
    }

    public func area() {
        width * height
    }
}

ps : class 只能定义在源文件顶层。

2. class成员变量

在类的架构中,成员变量依据其作用域与生命周期的不同,被明确区分为实例成员变量与静态成员变量两大类。静态成员变量,作为类级别共享的数据,通过static关键字进行标记,以突显其独特的存在方式。这些静态成员变量不仅要求在使用前必须被赋予初始值(尽管在某些语言或上下文中,这一要求可能有所放宽,但良好的编程实践鼓励明确初始化),而且它们的访问方式也与众不同——它们通常不依赖于类的任何特定实例,而是直接通过类名进行访问,这一特性体现了静态成员变量在类范围内的全局性和共享性。

相比之下,实例成员变量则紧密关联于类的每一个实例对象,是对象状态的具体体现。每个对象实例都拥有自己独立的实例成员变量副本,这些变量在对象被创建时随之诞生,并随着对象的生命周期而变化。实例成员变量的访问需要通过对象实例来进行,这反映了它们与对象实例之间的紧密绑定关系。

class Rectangle {
    let width = 10
    static let height = 20
}

let l = Rectangle.height // l = 20

在面向对象编程中,类的成员变量被细分为实例成员变量和静态成员变量。实例成员变量是那些与类的特定实例(即对象)紧密相关的变量。每个对象实例都拥有自己独立的实例成员变量副本,这些变量在对象被创建时根据需要进行初始化。

class Rectangle {
    let width = 10
    let height: Int64
    init(h: Int64){
        height = h
    }
}
let rec = Rectangle(20)
let l = rec.height // l = 20

3. class 静态初始化器

类允许定义一个静态初始化器,该初始化器以特定的关键字组合“static init”作为标识,其后紧跟一个没有参数的列表(尽管在多数语言中静态初始化器并不显式包含参数列表的声明),以及一个包含初始化逻辑的函数体。这个静态初始化器不能被访问修饰符(如public、private等)所修饰,因为它本质上是类的一部分初始化过程,而非一个可访问的成员。在静态初始化器的函数体内,必须包含对所有在声明时未直接初始化的静态成员变量的赋值表达式,以确保它们在类被使用前已经得到了正确的初始化。如果未能做到这一点,根据编译器的规则,可能会导致编译时报错。

class Rectangle {
    static let degree: Int64
    static init() {
        degree = 180
    }
}

最多允许定义一个静态初始化器

class Rectangle {
    static let degree: Int64
    static init() {
        degree = 180
    }
    static init() { // Error, redefinition with the previous static init function
        degree = 180
    }
}

4. class 构造

在面向对象编程中,类(class)与结构体(struct,在某些语言中可能更接近于类的概念)类似,都支持定义构造函数来初始化对象的实例成员变量。不过,需要注意的是,大多数现代编程语言中并没有直接使用“init”作为普通构造函数的特定关键字。相反,构造函数的名称通常与类名相同,或者遵循特定的命名约定。

class Rectangle {
    let width: Int64
    let height: Int64

    public init(width: Int64, height: Int64) { // Error, 'height' is not initialized in the constructor
        this.width = width
    }
}

一个类中可以定义多个普通构造函数,但它们必须构成重载

class Rectangle {
    let width: Int64
    let height: Int64

    public init(width: Int64) {
        this.width = width
        this.height = width
    }

    public init(width: Int64, height: Int64) { // Ok: overloading with the first init function
        this.width = width
        this.height = height
    }

    public init(height: Int64) { // Error, redefinition with the first init function
        this.width = height
        this.height = height
    }
}

除了可以定义额外的构造函数(这些构造函数在Kotlin中通常不直接以“init”为名,而是通过类名后跟参数列表来定义,并且可能需要使用constructor关键字显式声明,尽管这并非总是必需的),类(class)内部还可以包含一个主构造函数,其名称与类类型名相同。主构造函数的参数列表中可以包含两种类型的参数:普通参数,它们仅作为构造函数的输入;以及成员变量参数,这些参数在参数名前使用valvar关键字声明,它们不仅作为构造函数的输入,还同时定义了类的成员变量并完成了它们的初始化。使用主构造函数可以显著简化类的定义过程,因为它允许开发者在定义类时就直接初始化其成员变量。

class Rectangle {
    public Rectangle(let width: Int64, let height: Int64) {}
}

若一个类在定义时未包含任何自定义的构造函数(即没有显式地定义主构造函数或其他任何构造函数),且其所有实例成员变量均已在声明时指定了初始值,则编译器会自动为该类生成一个无参数的默认构造函数。通过调用这个自动生成的构造函数,可以创建出一个所有实例成员变量均被初始化为它们声明时指定值的对象实例。相反,如果类中定义了至少一个构造函数,则编译器不会自动生成这样的无参构造函数,除非开发者显式地声明了一个无参数的构造函数。

class Rectangle {
    let width = 10
    let height = 20

    /* Auto-generated parameterless constructor:
    public init() {
    }
    */
}

// Invoke the auto-generated parameterless constructor
let r = Rectangle() // r.width = 10,r.height = 20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攒了一袋星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值