Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program. -Linus Torvalds
In this lab, you'll construct some classes to represent different kinds of vehicles. We'll also cover the topic of inheritance with classes.
In this lab, the final lab in the classes unit, you'll be constructing some classes to represent different kinds of vehicles. You'll have to implement several methods according to a spec (described below in the Instructions section) in order to make a set of tests pass.
Before you get started, though, you have one concept left to learn: Inheritance.
Let's say you're creating a few classes to represent animals. Animals have a few common attributes: They have some number of legs (including zero legs in the case of animals like fish), and a species name. Animals can also make sounds. There are also specific kinds of animals, such as insects and cats, that have slightly different attributes.
In order to represent animals, you could create a class to contain those attributes. An Animal
class might look like this:
class Animal {
let speciesName: String
let numberOfLegs: Int
init(speciesName: String, numberOfLegs: Int) {
self.speciesName = speciesName
self.numberOfLegs = numberOfLegs
}
func speak() -> String {
return ""
}
}
Using this class as a base, you could create other animals, like horses, insects, and pet cats. These animals would all have the basic attributes in common, but would implement their own behavior and override the base animal's behavior, too.
To implement more specific animal classes, you can inherit from the base Animal
class.
A class that inherits from another implements some of the behavior of the base class, but can override or add new behavior, too. For example, here's an Insect
class that provides its own initializer, and also overrides the base Animal
's speak()
method, as well as adding a fly()
method.
class Insect: Animal {
init(speciesName: String) {
super.init(speciesName: speciesName, numberOfLegs: 6)
}
override func speak() -> String {
return "Bzzzz"
}
func fly() {
print("Flying!")
}
}
Let's examine what's happening here. First of all, the class definition looks a bit different. Instead of just class Insect
, you wrote class Insect: Animal
. The part after the colon indicates that Insect
inherits from Animal
. That means that an Insect
is an Animal
, and so can do everything an Animal
can do. It has properties like speciesName
and numberOfLegs
, just like an Animal
. But it also adds a fly()
method that only an Insect
would have.
Take a look at the initializer, too. It calls super.init(speciesName:numberOfLegs:)
, the Animal
class's initializer. super
refers to the superclass (the class that Insect
inherits from), and calls the superclass's initializer.
Insect
also overrides the speak()
method from Animal
to return "Bzzzz". In order to let the Swift compiler know that you are overriding a superclass's method, you mark it with the override
keyword. This lets Swift know that you didn't accidentally create a method with the same name as one in the superclass—you did, in fact, intend to override it.
A Cat
class might look like this:
class Cat: Animal {
let owner: String
init(owner: String) {
super.init(speciesName: "Feline", numberOfLegs: 4)
}
override func speak() -> String {
return "Meow!"
}
}
Now that you know about inheritance, let's get on with the lab!
In this lab, you'll create several classes, including some that inherit from others. This lab contains unit tests. When you first open the Xcode project, the tests will fail. You'll know you've successfully completed the lab when all the tests pass!
Open up CatchEmAll.xcworkspace
to get started.
The first class you must implement is the Vehicle
class, in Vehicle.swift
. Create a new class called Vehicle
. Vehicle should contain these properties:
- A constant
String
namedname
- A constant
Double
namedweight
- A constant
Double
namedmaxSpeed
- A variable
Double
namedspeed
- A variable
Double
namedheading
. (Note that this property should only accept values in the range 0 to 360.)
Vehicle
should also have an initializer that takes name,
weight, and
maxSpeedas parameters, and sets the appropriate properties. It should also set
speedand
heading` to 0.0.
You should also add these methods to Vehicle
. These methods take no parameters and return no values.
goFast()
, which sets the vehicle'sspeed
to itsmaxSpeed
.halt()
, which sets the vehicle'sspeed
to 0.accelerate()
, which increases the vehicle'sspeed
by ⅒ itsmaxSpeed
. It cannot increase the vehicle'sspeed
beyond itsmaxSpeed
.decelerate()
, which decreases the vehicle'sspeed
by ⅒ itsmaxSpeed
. It cannot decrease the vehicle'sspeed
below 0.turnRight()
, which increases the vehicle'sheading
by 90 and cuts itsspeed
in half. If the vehicle'sheading
increases beyond 360, it wraps around again (that is, if the heading would be increased to 375, it wraps around to 15 again). The vehicle cannot turn if it is stationary (has aspeed
of 0).turnLeft()
which decreases the vehicle'sheading
by 90 and cuts its speed in half. If the vehicle'sheading
decreases below 0, it wraps around again (that is, if it would decrease to -15, it would instead wrap around to 345). The vehicle cannot turn if it is stationery (has aspeed
of 0).
Create an enum in Vehicle.swift
called Transmission
. It should have two cases:
Automatic
Manual
Next, you need to implement the Car
class in Car.swift
. Car
should inherit from Vehicle
. It should add three new properties:
- A constant
Transmission
namedtransmission
- A constant
Int
calledcylinders
- A constant
Double
calledmilesPerGallon
Car
should also have an initializer that takes six parameters:
- A
String
calledname
- A
Double
calledweight
- A
Double
calledmaxSpeed
- A
Transmission
calledtransmission
- An
Int
calledcylinders
- A
Double
calledmilesPerGallon
The initializer should first set the parameters specific to Car
, then call super.init
with the parameters required by the Vehicle
superclass's initializer. Here's a hint: The Car
initializer should look like this:
init(name: String, weight: Double, maxSpeed: Double, transmission: Transmission, cylinders: Int, milesPerGallon: Double) {
self.transmission = transmission
self.cylinders = cylinders
self.milesPerGallon = milesPerGallon
super.init(name: name, weight: weight, maxSpeed: maxSpeed)
}
Finally, Car
should add two new methods, which again take no parameters and have no return value:
drive()
, which simply callssuper.accelerate()
brake()
, which simply callssuper.decelerate()
Next, implement a RaceCar
class in RaceCar.swift
. This class should inherit from Car
and add two new properties:
- A constant
String
nameddriver
- A variable
[String]
namedsponsors
This class should also implement an initializer that takes eight parameters:
- A
String
calledname
- A
Double
calledweight
- A
Double
calledmaxSpeed
- A
Transmission
calledtransmission
- An
Int
calledcylinders
- A
Double
calledmilesPerGallon
- A
String
calleddriver
- A
[String]
calledsponsors
The initializer should assign the driver
and sponsors
parameters to the appropriate properties, then call the superclass's initializer with the remaining parameters.
The RaceCar
class should also override two of Vehicle
's methods:
accelerate()
should increase the race car's speed by ⅕ (instead of ⅒).decelerate()
should decrease the race car's speed by ⅕ (instead of ⅒).
The RaceCar
class should also add two new methods, which take no parameters and return no values:
driftRight()
, which increases the race car'sheading
by 90, but only decreases the speed by ¼ of its current speed. The race car cannot drift if it is not moving at all.driftLeft()
, which decreases the race car'sheading
by 90, but only decreases the speed by ¼ of its current speed. The race car cannot drift if it is not moving at all.
Both cases should handle out of range heading
values the same as turnRight()
and turnLeft()
.
Next, create a Plane
class in Plane.swift
. This class should inherit from Vehicle
and add three new properties:
- A constant
Double
namedmaxAltitude
- A variable
Double
namedaltitude
- A calculated
Bool
namedinFlight
. This property should returntrue
if both thealtitude
andspeed
are greater than 0.
Plane
should have an initializer that takes four parameters:
- A
String
namedname
- A
Double
namedweight
- A
Double
namedmaxSpeed
- A
Double
namedmaxAltitude
This initializer should assign the parameter maxAltitude
to the maxAltitude
property, and also set the altitude
parameter to 0. It should then call the superclass's initializer with the remaining parameters.
Plane
should also add six more methods, each of which take no parameters and return no value:
takeOff()
, which sets the plane'sspeed
andaltitude
to ⅒ of their maximums, but only if the plane is not already in flight.land()
, which sets the plane'sspeed
andaltitude
to 0.climb()
, which increases the plane's altitude by ⅒ of the plane'smaxAltitude
and causes the plane to decelerate. It should not set the plane'saltitude
beyond itsmaxAltitude
, or reduce the speed below 0. The plane can only climb if it is in flight.dive()
, which decreases the plane's altitude by ⅒ of the plane'smaxAltitude
and causes the plane to accelerate. It should not set the plane'saltitude
below 0 or increase the plane'sspeed
beyond itsmaximumSpeed
. The plane can only dive if it is in flight.bankRight()
, which increases the plane'sheading
by 45 but only decreases the plane'sspeed
by ⅒ of its current value. The plane can only bank if it is in flight.bankLeft()
, which decreases the plane'sheading
by 45 but only decreases the plane'sspeed
by ⅒ of its current value. The plane can only bank if it is in flight.
The same rules for handling out of range heading
values apply to bankLeft()
and bankRight()
.
Finally, you should implement a class called Jet
in Jet.swift
. It should inherit from Plane
.
The Jet
class should override two of methods from Plane
:
- Override
climb()
to increase the jet's altitude by ⅕ of itsmaxAltitude
. Otherwise, the same rules forPlane
'sclimb()
should apply. - Override
dive()
to dcrease the jet's altitude by ⅕ of itsmaxAltitude
. Otherwise, the same rules forPlane
'sdive()
should apply.
The Jet
class should also add one new method, which takes no parameters and returns no value:
afterburner()
, which sets the jet'sspeed
to twice itsmaxSpeed
, but only if the jet is already flying at itsmaxSpeed
.
That's it! If the tests pass, you completed the lab. If the tests don't pass, look back over these directions and try to figure out what you did wrong. Good luck!
View Swift Classes All Lab on Learn.co and start learning to code for free.