Reputation: 5082
A super-class Car and a sub-class Jaguar was created. The function info() -> Void in the sub-class overrided the super-class' function. A instance named theAuto of type Jaguar had been created.
Problem:
Seems I cannot up casts the theAuto to the type of Car, please see the code snippet and its comments
class Car {
func info() {
print("You've got a car")
}
}
class Jaguar : Car {
override func info() {
print("You've got a Jaguar")
}
}
let theAuto = Jaguar()
theAuto.info() // --> You've got a Jaguar
let auto = theAuto as Car // casting but seems not working
auto.info() // --> You've got a Jaguar
print(type(of: auto)) // fail to casting
Question:
I think I didn't fully understand the concept of casting together with override scenario. Why I cannot make the up casting? Is the override action limited my upper casting?
many thanks for your help and time
Upvotes: 5
Views: 1231
Reputation: 80821
Because you're overriding the method in a subclass, you're getting dynamic dispatch. The method implementation to call will be based on the dynamic type of the instance that it's called on. Upcasting a Jaguar
to a Car
only changes the static type of the instance – the dynamic type is still a Jaguar
, for that's the type of instance you created.
Therefore upcasting has no bearing whatsoever on the dynamic dispatch of a method – nor should it, as the whole point of dynamic dispatch is to ensure that the correct method implementation for the given instance is called no matter what it's statically typed as.
The kind of behaviour you're expecting is static dispatch – the compiler chooses the implementation to call based on the static type of the instance. This is commonly achieved by overloading (rather than overriding) functions.
For example, an overloaded static
method:
class Car {
static func info(for car: Car) {
print("You've got a Car")
}
}
class Jaguar : Car {
static func info(for jaguar: Jaguar) {
print("You've got a Jaguar")
}
}
let jaguar = Jaguar()
Jaguar.info(for: jaguar) // You've got a Jaguar
Car.info(for: jaguar) // You've got a Car
let car = jaguar as Car
Jaguar.info(for: car) // You've got a Car
Here, the compiler resolves which implementation of info(for:)
to call based on the static types of what it's being called on and the arguments being passed. If it's either called on Car
, or the argument passed is statically typed as a Car
, only Car
's overload can possibly be statically dispatched to.
Another example of static dispatch is with a protocol extension, where the method isn't a protocol requirement (as making it a requirement gives it dynamic dispatch).
protocol Car {}
extension Car {
func info() {
print("You've got a Car")
}
}
class Jaguar : Car {
func info() {
print("You've got a Jaguar")
}
}
let jaguar = Jaguar()
jaguar.info() // You've got a Jaguar
let car = jaguar as Car
car.info() // You've got a Car
Here, the compiler resolves which implementation of info()
to call solely based on the static type of the instance that it's called on.
Upvotes: 4
Reputation: 32066
theAuto
is always a Jaguar
. It is also always a Car
. However, calling info()
will always return the implementation for the most specific type and so will always print
You've got a Jaguar
Regarding casting:
let car1 : Car = Jaguar()
let car2 : Car = BMW()
if let automobile = car1 as? Jaguar {
print ("The automobile is a Jaguar")
car1.info()
}
if let automobile = car2 as? Jaguar {
print ("The automobile is a Jaguar")
car2.info()
}
prints
The automobile is a Jaguar
You've got a Jaguar
Only the first section prints. The second car cannot be cast to a Jaguar, because it is a BMW.
Upvotes: 1