Hàm khởi tạo và super
Thuộc phần Lập trình hướng đối tượng trong hành trình Swift của Coddy. Bài học 24 trên 57.
Khi lớp con thêm một thuộc tính được lưu trữ mà không có giá trị mặc định, lớp đó cần có hàm khởi tạo riêng. Trước tiên, lớp đặt các thuộc tính của mình, sau đó gọi hàm khởi tạo của lớp cha bằng super.init(...):
class Animal {
let name: String
init(name: String) { self.name = name }
}
class Bird: Animal {
let canFly: Bool
init(name: String, canFly: Bool) {
self.canFly = canFly
super.init(name: name)
}
}
let p = Bird(name: "Pip", canFly: false)
print("\(p.name) \(p.canFly)")Đầu ra:
Pip falseThứ tự rất quan trọng: các thuộc tính của lớp con phải có giá trị trước khi super.init chạy, còn các thuộc tính được kế thừa chỉ có thể dùng sau đó. Swift kiểm tra điều này khi biên dịch:
init(name: String, canFly: Bool) {
// print(self.name) // lỗi: dùng self trước super.init
self.canFly = canFly // 1. các thuộc tính của chính lớp này
super.init(name: name) // 2. lớp cha
print(self.name) // 3. giờ có thể dùng mọi thứ
}Khi lớp con tự định nghĩa hàm khởi tạo, nó không còn kế thừa các hàm khởi tạo của lớp cha. Lớp con cũng có thể ghi đè hàm khởi tạo với cùng các tham số, bằng cách đánh dấu là override init:
class Timer {
var seconds: Int
init(seconds: Int) { self.seconds = seconds }
}
class SafeTimer: Timer {
override init(seconds: Int) {
super.init(seconds: max(0, seconds))
}
}
print(SafeTimer(seconds: -5).seconds)
print(SafeTimer(seconds: 30).seconds)Đầu ra:
0
30Mỗi cấp trong hệ thống phân cấp khởi tạo phần riêng của mình rồi chuyển phần còn lại cho lớp cha, nhờ đó mỗi thuộc tính trong chuỗi đều nhận giá trị đúng một lần:
class Vehicle {
let wheels: Int
init(wheels: Int) { self.wheels = wheels }
}
class Car: Vehicle {
let seats: Int
init(seats: Int) {
self.seats = seats
super.init(wheels: 4)
}
}
class Taxi: Car {
let company: String
init(company: String) {
self.company = company
super.init(seats: 5)
}
}
let t = Taxi(company: "City Cabs")
print("\(t.company): \(t.wheels) wheels, \(t.seats) seats")Đầu ra:
City Cabs: 4 wheels, 5 seatsThử thách
DễProduct lưu name và price (tính bằng cent). Khai báo lớp con DiscountedProduct với thuộc tính lưu trữ percent. Hàm khởi tạo nhận name, price và percent, lưu percent rồi gọi super.init với giá đã giảm theo phần trăm (làm tròn xuống). Giá trị percent nằm ngoài khoảng từ 0 đến 100 được tính là 0. Thêm phương thức label() vào DiscountedProduct, phương thức này trả về tea: 450 (10% off).
Code được cung cấp đọc các dòng theo định dạng name,price,percent, tạo một DiscountedProduct cho mỗi dòng và in ra label().
Đặt code của bạn trong Product.swift và DiscountedProduct.swift. main.swift chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
// Đoạn code đầu vào/đầu ra đã cho: giữ nguyên
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
let p = line.split(separator: ",").map { String($0) }
let item = DiscountedProduct(name: p[0], price: Int(p[1])!, percent: Int(p[2])!)
print(item.label())
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Lớp và đối tượng
Làm việc với tệpĐịnh nghĩa lớpPhương thức và selfHàm khởi tạoLớp là tham chiếuÔn tập: Thẻ thư viện2Struct và kiểu giá trị
StructNgữ nghĩa giá trịPhương thức thay đổiStruct hay classÔn tập: mặt hàng trong kho5Kế thừa
Lớp conGhi đè phương thứcHàm khởi tạo và superfinal và hệ phân cấpÔn tập: hệ phân cấp nhân viên8Các giao thức tiêu chuẩn
CustomStringConvertibleEquatableComparableHashableÔn tập: Sắp xếp tùy chỉnhTự luyện tập: Playground Swift