我注意到编译器不允许我用另一个存储值覆盖存储的属性(这似乎很奇怪):
class Jedi {
var lightSaberColor = "Blue"
}
class Sith: Jedi {
override var lightSaberColor = "Red" // Cannot override with a stored property lightSaberColor
}
但是,我允许使用计算属性执行此操作:
class Jedi {
let lightSaberColor = "Blue"
}
class Sith: Jedi {
override var lightSaberColor : String{return "Red"}
}
为什么我不允许给它另一个值?
为什么用存储的属性覆盖令人憎恶的东西,并用计算的一个犹太教来做?他们在想什么?
答案 0 :(得分:54)
为什么我不允许再给它一个值?
绝对允许您为继承的属性提供不同的值。如果在获取该初始值的构造函数中初始化该属性,并从派生类传递不同的值,则可以执行此操作:
class Jedi {
// I made lightSaberColor read-only; you can make it writable if you prefer.
let lightSaberColor : String
init(_ lsc : String = "Blue") {
lightSaberColor = lsc;
}
}
class Sith : Jedi {
init() {
super.init("Red")
}
}
let j1 = Jedi()
let j2 = Sith()
println(j1.lightSaberColor)
println(j2.lightSaberColor)
覆盖属性与赋予它新值不同 - 它更像是为类赋予不同的属性。实际上,当您覆盖计算属性时会发生这种情况:计算基类中属性的代码是由替换的代码,用于计算派生类中该属性的覆盖。
[是否]可以覆盖实际存储的属性,即具有其他行为的
lightSaberColor
?
除了观察者之外,存储的属性没有行为,因此实际上没有什么可以覆盖。通过上述机制可以赋予财产不同的价值。这正是问题中的示例试图用不同的语法实现的。
答案 1 :(得分:40)
对我来说,你的例子在Swift 3.0.1中不起作用。
在游乐场输入此代码:
class Jedi {
let lightsaberColor = "Blue"
}
class Sith: Jedi {
override var lightsaberColor : String {
return "Red"
}
}
在Xcode的编译时抛出错误:
不能覆盖不可变的'让' property' lightsaberColor'用一个' var'
的吸气剂
否则您无法更改存储属性的类型。 Liskov替换原则强制你允许在需要超类的地方使用子类。
但是如果将其更改为var
并因此在计算属性中添加set
,则可以使用相同类型的计算属性覆盖存储的属性。
class Jedi {
var lightsaberColor = "Blue"
}
class Sith: Jedi {
override var lightsaberColor : String {
get {
return "Red"
}
set {
// nothing, because only red is allowed
}
}
}
这是可能的,因为从存储的属性切换到计算属性是有意义的。
但是使用存储的var
属性覆盖存储的var
属性没有意义,因为您可以更改属性的值。
但是,您可以根本不使用存储的属性覆盖存储的属性。
我不会说西斯是绝地:-P。因此很明显,这不起作用。
答案 2 :(得分:13)
您可能想要为该属性指定另一个值:
class Jedi {
var lightSaberColor = "Blue"
}
class Sith: Jedi {
override init() {
super.init()
self.lightSaberColor = "Red"
}
}
答案 3 :(得分:10)
class SomeClass {
var hello = "hello"
}
class ChildClass: SomeClass {
override var hello: String {
set {
super.hello = newValue
}
get {
return super.hello
}
}
}
答案 4 :(得分:9)
对于Swift 4,来自Apple's documentation:
您可以覆盖要提供的继承实例或类型属性 您自己的该属性的自定义getter和setter,或者要添加 属性观察者使覆盖属性能够观察何时 基础财产价值变动。
答案 5 :(得分:3)
不幸的是,这在Swift中是不可能做到的。最好的替代方法如下:
class Jedi {
private(set) var lightsaberColor = "Blue"
}
class Sith: Jedi {
override var lightsaberColor : String {
get {
return "Red"
}
}
}
答案 6 :(得分:3)
Swift不允许您覆盖变量stored property
,相反,您可以使用computed property
class A {
var property1 = "A: Stored Property 1"
var property2: String {
get {
return "A: Computed Property 2"
}
}
let property3 = "A: Constant Stored Property 3"
//let can not be a computed property
func foo() -> String {
return "A: foo()"
}
}
class B: A {
//now it is a computed property
override var property1: String {
set { }
get {
return "B: overrode Stored Property 1"
}
}
override var property2: String {
get {
return "B: overrode Computed Property 2"
}
}
override func foo() -> String {
return "B: foo()"
}
//let can not be overrode
}
func testPoly() {
let a = A()
XCTAssertEqual("A: Stored Property 1", a.property1)
XCTAssertEqual("A: Computed Property 2", a.property2)
XCTAssertEqual("A: foo()", a.foo())
let b = B()
XCTAssertEqual("B: overrode Stored Property 1", b.property1)
XCTAssertEqual("B: overrode Computed Property 2", b.property2)
XCTAssertEqual("B: foo()", b.foo())
//B cast to A
XCTAssertEqual("B: overrode Stored Property 1", (b as! A).property1)
XCTAssertEqual("B: overrode Computed Property 2", (b as! A).property2)
XCTAssertEqual("B: foo()", (b as! A).foo())
}
与Java相比,它更加清楚,因为在编译时定义了类字段(有效运行),所以类字段不能被覆盖并且不支持多态。它称为变量隐藏 [About],不建议使用此技术,因为它很难阅读/支持
答案 7 :(得分:1)
我在为视图控制器设置常量时遇到了同样的问题。
由于我使用界面生成器来管理视图,因此无法使用init()
,因此我的解决方法与其他答案类似,不同之处在于,我在基类和继承类上均使用了只读计算变量。 / p>
class Jedi {
var type: String {
get { return "Blue" }
}
}
class Sith: Jedi {
override var type: String {
get { return "Red" }
}
}
答案 8 :(得分:0)
您还可以使用函数来覆盖。这不是直接的答案,但是可以丰富这个主题)
A级
override func viewDidLoad() {
super.viewDidLoad()
if shouldDoSmth() {
// do
}
}
public func shouldDoSmth() -> Bool {
return true
}
B级:A
public func shouldDoSmth() -> Bool {
return false
}
答案 9 :(得分:0)
如果您尝试在Swift 5中执行此操作,则会受到
的欢迎。不能用'var'的获取者覆盖不可变的'let'属性'lightSaberColor'
您最好的选择是将其声明为计算属性。
这是有效的,因为我们只是覆盖get {}
函数
class Base {
var lightSaberColor: String { "base" }
}
class Red: Base {
override var lightSaberColor: String { "red" }
}
答案 10 :(得分:-1)
您可以使用此方法更新值
class A {
var lightSaberColor : String = "Red"
}
您不需要覆盖变量。您可以更改变量的值。
class B: A {
* **Change Value when the class will initialize.**
override init() {
super.init()
self.lightSaberColor = "Orange"
}
/*
* **Change Value when you will use this function.**
*/
func test() {
lightSaberColor = "Green"
}
}
let b = B()
b.test()