【问题标题】:how to cast up to super class when there is an override function in the sub class当子类中有覆盖函数时如何转换为超类
【发布时间】:2017-03-31 10:22:33
【问题描述】:

创建了一个超类Car和一个子类Jaguar。子类中的函数 info() -> Void 覆盖了超类的函数。 Jaguar 类型的名为 theAuto 的实例已创建。

问题:

似乎我无法将 theAuto 转换为 Car 的类型,请参阅代码 sn-p 及其 cmets

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

问题:

我想我没有完全理解强制转换和覆盖场景的概念。为什么我不能补铸?覆盖操作是否限制了我的上限转换?

非常感谢您的帮助和时间

【问题讨论】:

  • 如果要调用 Car 类的 info 方法,必须创建 Car 实例。如果您不覆盖 info 方法,它只会在这种情况下调用。如果你覆盖它的超类中的任何方法,那么它总是调用子类方法。
  • @Sahil 我将行从“let Car = Jaguar()”更改为“let auto:Car = Jaguar()”,但它不起作用
  • 你可以通过基类的超类的实例来创建基类的对象,这样对象就可以指向它自己的每一个成员和它的超类。

标签: swift class types casting


【解决方案1】:

因为您要覆盖子类中的方法,所以您将获得动态调度。要调用的方法实现将基于调用它的实例的动态类型。将Jaguar 向上转换为Car 只会更改实例的静态 类型——动​​态类型仍然是Jaguar,因为那是您创建的实例的类型。

因此向上转换对方法的动态调度没有任何影响——也不应该,因为动态调度的全部意义在于确保调用给定实例的正确方法实现无论如何 它的静态类型是什么。

您期望的行为类型是 static 调度——编译器根据实例的静态类型选择要调用的实现。这通常通过重载(而不是覆盖)函数来实现。

例如一个重载的static方法:

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

在这里,编译器根据被调用对象的静态类型和传递的参数来解析要调用info(for:) 的哪个实现。如果在Car 上调用它,或者传递的参数被静态类型为Car,则只有Car 的重载可能被静态分派到。

静态分派的另一个例子是协议扩展,其中方法不是协议要求(因为使其成为要求赋予它动态分派)。

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

在这里,编译器仅根据调用它的实例的静态类型来解析要调用 info() 的哪个实现。

【讨论】:

  • 感谢您的帮助
  • 乐于帮助@SLN :)
【解决方案2】:

theAuto 始终是 Jaguar。它也始终是Car。但是,调用 info() 将始终返回最具体类型的实现,因此将始终打印

你有一辆捷豹


关于选角:

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()
}

打印

汽车是捷豹
你有一辆捷豹

仅打印第一部分。第二辆车不能投给捷豹,因为它是宝马。

【讨论】:

  • 那么它很自然,car2 是 Car 的实例和 BMW 的对象,因此它不会响应 Jaguar。
猜你喜欢
  • 2021-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-04
  • 1970-01-01
相关资源
最近更新 更多