如何在其子类中修改类的属性?

时间:2017-01-18 20:56:33

标签: swift inheritance override overloading

class Animals{
    var name : String = "default"
    var age : Int = 0
    func Details()-> String{
        return "This animal is a \(name) and has \(age) years old."
    }
}


class Dogs : Animals{
    name = "dog"
}

class Cats : Animals{
    name = "cat"
}

var MyAnimal = Dogs()

我希望看到这样的信息:"这只动物是一只狗,已经0岁了。" 但每次我收到这个:"这只动物是默认的,已经0岁了。"

var HisAnimal = Cats()

4 个答案:

答案 0 :(得分:2)

如果您想要存储而非计算的属性,可以在初始值设定项中设置name,如下所示:

class Animal {
    let name: String
    var age: Int = 0
    /* designated initializer: fully initializes all instance properties */
    init(name: String) {
        self.name = name
    }
    func details() -> String {
        return "This animal is a \(name) and has \(age) years old."
    }
}


class Dog : Animal {
    /* designated initializer of subclass: must call a designated
       initializer from its immediate superclass                   */
    init() {
        super.init(name: "dog")
    }
}

class Cat : Animal {
    /* ... */
    init() {
        super.init(name: "cat")
    }
}

let myAnimal = Dog()

此机制确保name仅从一个位置设置,并显式传递给初始化程序。

答案 1 :(得分:1)

或者在类

上使用协议(和泛型)

您很可能会创建Cat:s和Dog:s的实例,但您可能不希望为抽象的奇怪Animal:s创建实例。 Animal作为常见超类的替代方法是让它成为协议。

protocol Animal {
    static var species: String { get }
    var name: String? { get }
    var age: Int { get set }
    var details: String { get }
}

extension Animal {
    static var species: String { return "\(self)".lowercased() }

    // since all the properties used in 'details' are blueprinted,
    // we might as well supply a default implementation of it.
    var details: String {
        return "This animal is a \(Self.species)\(name.map{ " named \($0)" } ?? ""), aged \(age)."
    }
}

struct Dog: Animal {
    let name: String?
    var age: Int

    init(age: Int, name: String? = nil) {
        self.name = name
        self.age = age
    }
}

var myDog = Dog(age: 3, name: "Fred")
print(myDog.details) // This animal is a dog named Fred, aged 3.
myDog.age = 4 // grats to Fred!
print(myDog.details) // This animal is a dog named Fred, aged 4.

let wildDog = Dog(age: 6) // never named ...
print(wildDog.details) // This animal is a dog, aged 3.

请注意,我选择使用类属性species来命名每只动物的种类,并为那些被赋予名称的动物保留实例属性name;比如,你的亲爱的狗名为Fred(而不是你亲爱的狗dog)。

使用协议也可以自然地选择泛型而不是类型化的抽象类型(后者在使用公共超类时可能很诱人):

struct Cat: Animal {
    let name: String?
    var age: Int

    init(age: Int, name: String? = nil) {
        self.name = name
        self.age = age
    }
}

var wildCat = Cat(age: 2)

func yieldBirthday<T: Animal>(for animal: inout T) {
    print(animal.details)
    animal.age += 1
    print("This \(T.species) now had a birthday!")
    print(animal.details)
}

yieldBirthday(for: &myDog)
/* This animal is a dog named Fred, aged 4.
   This dog now had a birthday!
   This animal is a dog named Fred, aged 5. */

yieldBirthday(for: &wildCat)
/* This animal is a cat, aged 2.
   This cat now had a birthday!
   This animal is a cat, aged 3. */

答案 2 :(得分:0)

解决的一种方法是使用&#34;模板方法模式&#34;

class Animals {
    lazy var name : String = self.defaultName
    var defaultName:String { return "default" }

    func Details()-> String{
        return "This animal is a \(name) and has \(age) years old."
    }
}

class Dogs : Animals {
    override var defaultName:String { return "dog" }
}

另一种方法是为每个子类创建init方法并覆盖默认值

答案 3 :(得分:0)

通过创建初始化程序来设置名称(使用默认值),我将通过以下方式执行此操作:

class Animal: CustomStringConvertible {
    let name: String
    let age: Int

    init(name: String = "default", age: Int = 0) { // FIXME: Does a default age of 0 make sense?
        self.name = name
        self.age = age
    }

    public var description: String {
        return "This animal is a \(name) and is \(age) years old."
    }
}


class Dog: Animal {
    init() {
        super.init(name: "Dog")
    }
}

class Cat: Animal {
    init() {
        super.init(name: "Cat")
    }
}

var myAnimal = Dog()
print (myAnimal)