Controlling whether subclasses can or cannot override members

The following lines show the code for the complete Dog class that inherits from DomesticMammal. Note that the following code replaces the previous Dog class that just declared an overridden type property. The code file for the sample is included in the swift_3_oop_chapter_04_07 folder:

    open class Dog: DomesticMammal { 
      open static override var numberOfLegs: Int { 
        get { 
          return 4; 
        } 
      } 
     
      open static override var abilityToFly: Bool { 
        get { 
          return false; 
        } 
      } 
     
      open var breed: String { 
        get { 
          return "Just a dog" 
        } 
      } 
     
      open var breedFamily: String { 
        get { 
          return "Dog" 
        } 
      } 
     
      private func initializeDog() { 
        print("Dog created") 
      } 
     
      override init(age: Int, name: String, favoriteToy: String) { 
        super.init(age: age, name: name, favoriteToy: favoriteToy) 
        initializeDog() 
      } 
     
      override init(age: Int, isPregnant: Bool, name: String, 
      favoriteToy: String) { 
        super.init(age: age, isPregnant: isPregnant, name: name, 
        favoriteToy: favoriteToy) 
        initializeDog() 
      } 
     
      public final func printBreed() { 
        print(breed) 
      } 
     
      public final func printBreedFamily() { 
        print(breedFamily) 
      } 
     
      open func printBark(times: Int, otherDomesticMammal: 
      DomesticMammal?, isAngry: Bool) { 
        var bark = "(name)" 
        if let unwrappedOtherDomesticMammal = otherDomesticMammal { 
          bark += " to (unwrappedOtherDomesticMammal.name): " 
        } else { 
          bark += ": " 
        } 
        if isAngry { 
          bark += "Grr " 
        } 
        for _ in 0 ..< times { 
          bark += "Woof " 
        } 
        print(bark) 
      } 
     
      open func bark() { 
        printBark(times: 1, otherDomesticMammal: nil, isAngry: false) 
      } 
     
      open func bark(times: Int) { 
        printBark(times: times, otherDomesticMammal: nil, 
        isAngry: false) 
      } 
     
      open func bark(times: Int, otherDomesticMammal: DomesticMammal) { 
        printBark(times: times, otherDomesticMammal: herDomesticMammal, 
        isAngry: false) 
      } 
 
      open func bark(times: Int, otherDomesticMammal: DomesticMammal, 
      isAngry: Bool) { 
        printBark(times: times, otherDomesticMammal: 
        otherDomesticMammal, isAngry: isAngry) 
      } 
     
      open override func talk() { 
        bark() 
      } 
    } 

The Dog class overrides the talk method inherited from DomesticMammal. As it happened with the overridden properties in other subclasses, we just add the override keyword to the method declaration. The method doesn't invoke the method with the same name for its superclass, that is, we don't use the super keyword to invoke the talk method defined in DomesticMammal. The talk method in the Dog class invokes the bark method without parameters because dogs don't talk; they bark.

The bark method is overloaded with four declarations with different arguments. The following lines show the four different declarations included within the class body:

    open func bark() 
    open func bark(times: Int) 
    open func bark(times: Int, otherDomesticMammal: DomesticMammal) 
    open func bark(times: Int, otherDomesticMammal: DomesticMammal, 
    isAngry: Bool) 

This way, we can call any of the defined bark methods based on the provided arguments. The four methods end up invoking the printBark open method with different default values for the arguments not provided in the call to bark. The method builds and prints a message according to the specified number of times (times), the optional destination domestic mammal (otherDomesticMammal), and whether the dog is angry or not (isAngry).

The Dog class overrides the abilityToFly type property with the static keyword. This way, subclasses of dog won't be able to override this type property to return a different value because there is no known dog breed that can fly. The class also declares two read-only computed properties: breed and breedFamily. We will override their getters in the subclasses of Dog. The printBreed instance method displays the value of the breed computed property, and the printBreedFamily instance method displays the value of the breedFamily computed property. We won't override these instance methods in the subclasses because we just need to override the values of the properties to achieve our goals; therefore, we declared both the methods with the final keyword.

Tip

Those methods use the public access level because they are accessible but not overridable outside the defining module. The open access level is both accessible and overridable; therefore, it cannot be used in conjunction with the final keyword, which makes the methods non-overridable.

The following lines show the declarations of both methods with the final keyword, which prevents the subclasses from overriding these methods:

    public final func printBreed() 
    public final func printBreedFamily() 

If we call these instance methods from an instance of a subclass of Dog, they will execute the code specified in the Dog class, but the code will use the value of the properties overridden in the subclasses. Thus, we will see the messages displaying the values of the properties as defined in the subclasses.

We want to override both the printALeg and printAChild type methods inherited from Animal in a subclass of Dog. We declared both properties with the static keyword, so we will only be able to override them if we replace this keyword with class. The following lines show the code that replaces the declaration of both the properties in the Animal class. Note that the rest of the code for the Animal class remains without changes. The code file for the sample is included in the swift_3_oop_chapter_04_08 folder:

    open class func printALeg() { 
      preconditionFailure("The pringALeg method must be overriden") 
    } 
     
    open class func printAChild() { 
      preconditionFailure("The printChild method must be overriden") 
    } 

The following lines show the code for the TerrierDog class that inherits from Dog. The code file for the sample is included in the swift_3_oop_chapter_04_08 folder:

    open class TerrierDog: Dog { 
      open override class var averageNumberOfChildren: Int { 
        get { 
          return 5; 
        } 
      } 
     
      open override var breed: String { 
        get { 
          return "Terrier dog" 
        } 
      } 
     
      open override var breedFamily: String { 
         
        get { 
          return "Terrier" 
        } 
      } 
     
      private func initializeTerrierDog() { 
        print("TerrierDog created") 
      } 
     
      override init(age: Int, name: String, favoriteToy: String) { 
        super.init(age: age, name: name, favoriteToy: favoriteToy) 
        initializeTerrierDog() 
      } 
     
      override init(age: Int, isPregnant: Bool, name: String, 
      favoriteToy: String) { 
        super.init(age: age, isPregnant: isPregnant, name: name, 
        favoriteToy: favoriteToy) 
        initializeTerrierDog() 
      } 
     
      open override class func printALeg() { 
        print("|", terminator: String()) 
      } 
     
      open override class func printAChild() { 
        // Print a dog's face emoji 
        print(String(UnicodeScalar(0x01f436)!), terminator: String()) 
           
      } 
    } 

As it happened in the other subclasses that we coded, we have more than one initializer defined for the class. In this case, one of the initializers requires age, name, and favoriteToy to create an instance of the TerrierDog class, and we also have an initializer that adds an isPregnant argument. Both initializers invoke the superclass's initializer and then call the private initializeTerrierDog method. This method prints a message indicating that a TerrierDog class is created. The class overrides the getter methods to return "Terrier dog" and "Terrier" as the values for the breed and breedFamily computed properties that were defined in the superclass and overridden in this class.

In addition, the class overrides the getter method for the averageNumberOfChildren type property. However, in this case, the overridden type property declaration uses the class keyword because we want to enable the subclasses of TerrierDog to be able to override this type property. The Terrier family is huge, and some of the members of this family have a different average number of children.

The class also overrides both the printALeg and printAChild type methods inherited from Animal. The printALeg method prints a pipe symbol (|), and the printAChild method prints a dog's face emoji.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.102.160