virtuales una subprogramas pura modificador metodos herencia funcion entre diferencia declara como virtual-method swift dynamic-dispatch

virtual method - una - ¿Swift tiene un despacho dinámico y métodos virtuales?



subprogramas virtuales c++ (5)

A diferencia de C ++, no es necesario designar que un método es virtual en Swift. El compilador determinará cuál de los siguientes usar:

(Las métricas de rendimiento, por supuesto, dependen del hardware)

  • En línea el método: 0 ns
  • Despacho estático: <1.1ns
  • Despacho virtual 1.1ns (como Java, C # o C ++ cuando se designa).
  • Despacho dinámico 4.9ns (como Objective-C).

Objective-C, por supuesto, siempre utiliza este último. La sobrecarga de 4.9ns no suele ser un problema, ya que representaría una pequeña fracción del tiempo total de ejecución del método. Sin embargo, cuando sea necesario, los desarrolladores podrían recurrir sin problemas a C o C ++. En Swift, sin embargo, el compilador analizará cuál de los más rápidos puede usarse e intentará decidir en su nombre, favoreciendo los mensajes en línea, estáticos y virtuales, pero conservando la interoperabilidad de Objective-C. Es posible marcar un método con dynamic para fomentar la mensajería.

Un efecto colateral de esto, es que algunas de las características poderosas que ofrece el envío dinámico pueden no estar disponibles, como se podría haber asumido anteriormente para cualquier método de Objective-C. El envío dinámico se utiliza para la interceptación de métodos, que a su vez se utiliza para:

  • Observadores de propiedades de estilo cacao.
  • Instrumentación del objeto modelo CoreData.
  • Programación Orientada a Aspectos

Los tipos de características anteriores son los que ofrece un lenguaje de late binding . Tenga en cuenta que si bien Java utiliza vtable dispatch para la invocación de métodos, todavía se considera un lenguaje de enlace tardío y, por lo tanto, es capaz de las características anteriores en virtud de tener una máquina virtual y un sistema de carga de clases, que es otro método para proporcionar instrumentación en tiempo de ejecución. Swift "puro" (sin interoperabilidad de Objective-C) es como C ++ en que es un lenguaje compilado directo a ejecutable con envío estático, entonces estas características dinámicas no son posibles en tiempo de ejecución. En la tradición de ARC, es posible que veamos más de este tipo de características que se mueven al tiempo de compilación, lo que le da una ventaja con respecto al "rendimiento por vatio", una consideración importante en la computación móvil.

Llegando de un fondo en C ++ / Java / C # esperaba ver métodos virtuales en Swift, sin embargo, al leer la documentación rápida no veo ninguna mención de los métodos virtuales.

¿Qué me estoy perdiendo?


A partir de Xcode 8.xx y 9 Beta, los métodos virtuales en C ++ podrían traducirse en Swift 3 y 4 de esta manera:

protocol Animal: AnyObject { // as a base class in C++; class-only protocol in Swift func hello() } extension Animal { // implementations of the base class func hello() { print("Zzz..") } } class Dog: Animal { // derived class with a virtual function in C++ func hello() { print("Bark!") } } class Cat: Animal { // another derived class with a virtual function in C++ func hello() { print("Meow!") } } class Snoopy: Animal { // another derived class with no such a function // }

Darle una oportunidad.

func test_A() { let array = [Dog(), Cat(), Snoopy()] as [Animal] array.forEach() { $0.hello() } // Bark! // Meow! // Zzz.. } func sayHello<T: Animal>(_ x: T) { x.hello() } func test_B() { sayHello(Dog()) sayHello(Cat()) sayHello(Snoopy()) // Bark! // Meow! // Zzz.. }

En resumen, creo que las cosas similares que hacemos en C ++ se pueden lograr con Protocol y Generic en Swift.

También vine del mundo de C ++ y me enfrenté a la misma pregunta. Lo anterior parece funcionar, pero parece una forma de C ++, aunque no de una forma un tanto Swifty.

Cualquier otra sugerencia será bienvenida!


Swift fue hecho para ser fácil de aprender para los programadores de Objective-C, y en Objective-C no hay métodos virtuales, al menos no de la forma en que podrías pensar en ellos. Si busca instrucciones sobre cómo crear una clase abstracta o un método virtual en Objective-C aquí en SO, generalmente es un método normal que simplemente lanza una excepción y bloquea la aplicación. (Lo que tiene sentido, porque se supone que no debes llamar a un método virtual)

Por lo tanto, si la documentación de Swift no dice nada sobre los métodos virtuales, supongo que, al igual que en Objective-C, no hay ninguno.


Todos los métodos son virtuales; sin embargo, debe declarar que está anulando un método de una clase base usando la palabra clave de override :

De la Guía de Programación Swift :

Primordial

Una subclase puede proporcionar su propia implementación personalizada de un método de instancia, método de clase, propiedad de instancia o subíndice que, de lo contrario, heredaría de una superclase. Esto se conoce como anulación.

Para anular una característica que de otro modo se heredaría, prefija su definición de anulación con la palabra clave de override . Al hacerlo, se aclara que tiene la intención de proporcionar una anulación y no ha proporcionado una definición coincidente por error. La anulación por accidente puede provocar un comportamiento inesperado, y cualquier anulación sin la palabra clave de override se diagnostica como un error cuando se compila el código.

La palabra clave de override también solicita al compilador Swift que verifique que la superclase de la clase de anulación (o uno de sus padres) tenga una declaración que coincida con la que proporcionó para la anulación. Esta comprobación garantiza que su definición de reemplazo sea correcta.


class A { func visit(target: Target) { target.method(self); } } class B: A {} class C: A { override func visit(target: Target) { target.method(self); } } class Target { func method(argument: A) { println("A"); } func method(argument: B) { println("B"); } func method(argument: C) { println("C"); } } let t = Target(); let a: A = A(); let ab: A = B(); let b: B = B(); let ac: A = C(); let c: C = C(); a.visit(t); ab.visit(t); b.visit(t); ac.visit(t); c.visit(t);

Tenga en cuenta la self referencia en la visit() de A y C Al igual que en Java, no se copia, sino que self mantiene el mismo tipo hasta que se usa de nuevo en una anulación.

El resultado es A, A, A, C, C, por lo que no hay un envío dinámico disponible. Desafortunadamente.