We can combine class inheritance with protocol conformance. The following lines show the code for a new AngryCatAlien
class that inherits from the AngryCat
class and conforms to the Alien
protocol. Note that the class declaration includes the superclass (AngryCat
) and the implemented protocol (Alien
) separated by a comma after the colon (:
). The code file for the sample is included in the swift_3_oop_chapter_05_09
folder:
open class AngryCatAlien : AngryCat, Alien {
open var numberOfEyes: Int = 0
init (nickName: String, age: UInt, fullName: String,
initialScore: UInt, x: UInt, y: UInt, numberOfEyes: Int) {
super.init(nickName: nickName, age: age, fullName: fullName,
initialScore: initialScore, x: x, y: y)
self.numberOfEyes = numberOfEyes
}
open func appear() {
print("I'm (fullName) and you can see my (numberOfEyes)
eyes.")
}
open func disappear() {
print("(fullName) disappears.")
}
}
As a result of the previous code, we have a new class named AngryCatAlien
that conforms to the following three protocols:
ComicCharacter
: This is implemented by the AngryCat
superclass and inherited by AngryCatAlien
GameCharacter
: This is implemented by the AngryCat
superclass and inherited by AngryCatAlien
Alien
: This is implemented by AngryCatAlien
The initializer adds a numberOfEyes
argument to the argument list defined in the base initializer, that is, the initializer defined in the AngryCat
superclass. In this case, the initializer calls the base initializer (self.init
) and then initializes the numberOfEyes
property with the value received in the numberOfEyes
argument. The class implements the appear
and disappear
methods required by the Alien
protocol.
The following lines show the code for a new AngryCatWizard
class that inherits from the AngryCat
class and implements the Wizard
protocol. Note that the class declaration includes the superclass (AngryCat
) and the implemented protocol (Wizard
) separated by a comma after the colon (:
). The code file for the sample is included in the swift_3_oop_chapter_05_09
folder:
open class AngryCatWizard: AngryCat, Wizard {
open var spellPower: Int = 0
open func disappear(alien: Alien) {
print("(fullName) uses his (spellPower) spell power to make
the alien with (alien.numberOfEyes) eyes disappear.")
}
init (nickName: String, age: UInt, fullName: String,
initialScore: UInt, x: UInt, y: UInt, spellPower: Int) {
super.init(nickName: nickName, age: age, fullName: fullName,
initialScore: initialScore, x: x, y: y)
self.spellPower = spellPower
}
}
As with the AngryCatAlien
class, the new AngryCatWizard
class implements three protocols. Two of these protocols are implemented by the AngryCat
superclass and inherited by AngryCatWizard
: ComicCharacter
and GameCharacter
. The AngryCatWizard
class adds the implementation of the Wizard
protocol.
The initializer adds a spellPower
argument to the argument list defined in the base constructor (super.init
), which is the constructor defined in the AngryCat
superclass. The constructor calls the base constructor and then initializes the spellPower
property with the value received in the spellPower
argument. The class implements the disappear
method, which receives an Alien
instance as an argument, required by the Wizard
protocol.
The disappear
method receives an Alien
as an argument. Thus, any instance of AngryCatAlien
would qualify as an argument for this method, that is, any instance of any class that conforms to the Alien
protocol.
The following lines show the code for a new AngryCatKnight
class, which inherits from the AngryCat
class and implements the Knight
protocol. Note that the class declaration includes the superclass (AngryCat
) and implemented protocol (Knight
) separated by a comma after the colon (:
). The code file for the sample is included in the swift_3_oop_chapter_05_09
folder:
open class AngryCatKnight : AngryCat, Knight {
open var swordPower: Int = 0
open var swordWeight: Int = 0
private func writeLinesAboutTheSword() {
print("(fullName) unsheaths his sword.")
print("Sword power: (swordPower). Sword weight:
(swordWeight).")
}
open func unsheathSword() {
writeLinesAboutTheSword()
}
open func unsheathSword(target: Alien) {
writeLinesAboutTheSword()
print("The sword targets an alien with (target.numberOfEyes)
eyes.")
}
init (nickName: String, age: UInt, fullName: String,
initialScore: UInt, x: UInt, y: UInt, swordPower: Int,
swordWeight: Int) {
super.init(nickName: nickName, age: age, fullName: fullName,
initialScore: initialScore, x: x, y: y)
self.swordPower = swordPower
self.swordWeight = swordWeight
}
}
As with the two previously coded classes inherited from the AngryCat
class and conforming to the protocols, the new AngryCatKnight
class implements three protocols. Two of these protocols are implemented by the AngryCat
superclass and inherited by AngryCatKnight
: ComicCharacter
and GameCharacter
. The AngryCatKnight
class adds the implementation of the Knight
protocol.
The initializer adds the swordPower
and swordWeight
arguments to the argument list defined in the base initializer (base.init
), which is the constructor defined in the AngryCat
superclass. The initializer calls the base initializer (base.init
) and then initializes the swordPower
and swordWeight
properties with the values received in the swordPower
and swordHeight
arguments.
The class implements the two versions of the unsheathSword
method required by the Knight
protocol. Both methods call the private writeLinesAboutTheSword
method, and the overloaded version that receives Alien
as an argument prints an additional message about the alien that the sword has as a target---specifically, the number of eyes.
The following table summarizes the list of protocols to which each of the classes we created conform:
Class name |
Conforms to the following protocol(s) |
|
|
|
|
|
|
|
|
|
|
The following simplified UML diagram shows the hierarch tree for the classes and their relationships with protocols:
The following UML diagram shows the protocols and the classes with their properties and methods. We can use the diagram to understand all the things that we will analyze with the next code samples based on the usage of these classes and the previously defined protocols:
The following lines create one instance of each of the previously created classes. The code file for the sample is included in the swift_3_oop_chapter_05_09
folder:
var angryDog1 = AngryDog(nickName: "Bailey") var angryCat1 = AngryCat(nickName: "Bella", age: 3, fullName: "Mrs. Bella", initialScore: 20, x: 10, y: 10) var angryCatAlien1 = AngryCatAlien(nickName: "Lucy", age: 4, fullName: "Mrs. Lucy", initialScore: 50, x: 20, y: 10, numberOfEyes: 3) var angryCatWizard1 = AngryCatWizard(nickName: "Daisy", age: 4, fullName: "Mrs. Daisy", initialScore: 50, x: 20, y: 10, spellPower: 6) var angryCatKnight1 = AngryCatKnight(nickName: "Maggie", age: 3, fullName: "Mrs. Maggy", initialScore: 1300, x: 40, y: 10, swordPower: 7, swordWeight: 5)
The following table summarizes the instance name and its class name:
Instance name |
Class name |
|
|
|
|
|
|
|
|
|
|
Now, we will evaluate many expressions that use the is
keyword to determine whether the instances are an instance of the specified class or conform to a specific protocol. Note that all the expressions are evaluated to true
because every instance is of the type specified on the right-hand side after the is
keyword. The specified types are the main class for the instance, its superclass, or a class that conforms to the protocol.
For example, angryCatWizard1
is an instance of AngryCatWizard
. In addition, angryCatWizard1
belongs to AngryCat
because AngryCat
is the superclass of the AngryCatWizard
class. It is also true that angryCatWizard1
conforms to three protocols: ComicCharacter
, GameCharacter
, and Wizard
. The superclass of AngryCatWizard
---that is, AngryCat
---conforms to two of these protocols: ComicCharacter
and GameCharacter
. Therefore, AngryCatWizard
inherits the protocol conformance. Finally, the AngryCatWizard
class not only inherits from AngryCat
but also conforms to the Wizard
protocol. If we execute the following lines in the Playground, all of them will print true
as a result. The code file for the sample is included in the swift_3_oop_chapter_05_09
folder:
print(angryDog1 is AngryDog) print(angryDog1 is ComicCharacter) print(angryCat1 is AngryCat) print(angryCat1 is ComicCharacter) print(angryCat1 is GameCharacter) print(angryCatAlien1 is AngryCat) print(angryCatAlien1 is AngryCatAlien) print(angryCatAlien1 is ComicCharacter) print(angryCatAlien1 is GameCharacter) print(angryCatAlien1 is Alien) print(angryCatWizard1 is AngryCat) print(angryCatWizard1 is AngryCatWizard) print(angryCatWizard1 is ComicCharacter) print(angryCatWizard1 is GameCharacter) print(angryCatWizard1 is Wizard) print(angryCatKnight1 is AngryCat) print(angryCatKnight1 is AngryCatKnight) print(angryCatKnight1 is ComicCharacter) print(angryCatKnight1 is GameCharacter) print(angryCatKnight1 is Knight)
The following screenshot shows the result of executing the previous lines in the Playground. Note that the Playground uses a warning icon to let us know that all the expressions that include the is
keyword will always be evaluated to true
. In these cases, the compiler generates a warning:
3.12.136.186