poo - funciones de objetos en c++
¿Por qué una función no es un objeto? (3)
Leí en las normas n4296 (Borrador) § 1.8 página 7:
Un objeto es una región de almacenamiento. [Nota: una función no es un objeto, independientemente de si ocupa o no el almacenamiento de la forma en que lo hacen los objetos. -finalizar nota]
Pasé algunos días en la red buscando una buena razón para tal exclusión, sin suerte. Tal vez porque no entiendo completamente los objetos. Asi que:
- ¿Por qué una función no es un objeto? ¿Cómo difiere?
- ¿Y tiene esto alguna relación con los funtores (objetos de función)?
¿Por qué una función no es un objeto? ¿Cómo difiere?
Para entender esto, avancemos de abajo hacia arriba en términos de abstracciones involucradas. Entonces, usted tiene su espacio de direcciones a través del cual puede definir el estado de la memoria y debemos recordar que fundamentalmente se trata de este estado en el que opera.
De acuerdo, avancemos un poco más en términos de abstracciones. No estoy tomando ninguna abstracción impuesta por un lenguaje de programación todavía ( como objeto, matriz, etc. ) pero simplemente como laico quiero guardar un registro de una parte de la memoria, vamos a llamarlo Ab1
y otro llamado Ab2
.
Ambos tienen un estado fundamentalmente, pero tengo la intención de manipular / hacer uso del estado de manera diferente .
De manera diferente ... ¿Por qué y cómo?
Por qué ?
Debido a mis requisitos (para realizar la adición de 2 números y almacenar el resultado, por ejemplo). Ab1
usar Ab1
como un estado de uso prolongado y Ab2
como un estado de uso relativamente más corto. Entonces, crearé un estado para Ab1
( con los 2 números para agregar ) y luego usaré este estado para poblar parte del estado de Ab2
( Ab2
temporalmente ) y realizaré una mayor manipulación de Ab2
(los Ab2
) y guardaré una parte de la resultante Ab2
a Ab1
( el resultado agregado ). Publica que Ab2
vuelve inútil y restablecemos su estado.
¿Cómo?
Voy a necesitar un poco de administración de ambas partes para hacer un seguimiento de qué palabras elegir de Ab1
y copiar a Ab2
y así sucesivamente. En este punto me doy cuenta de que puedo hacer que funcione para realizar algunas operaciones simples, pero algo serio requerirá una especificación establecida para administrar esta memoria.
Por lo tanto, busco tal especificación de gestión y resulta que existe una variedad de estas especificaciones ( algunas tienen un modelo de memoria incorporado, otras ofrecen flexibilidad para administrar la memoria ) con un mejor diseño. De hecho, porque ( sin siquiera dictar cómo administrar la memoria directamente ) han definido con éxito la encapsulación para este almacenamiento de larga duración y las reglas sobre cómo y cuándo se puede crear y destruir.
Lo mismo ocurre con Ab2
pero la forma en que lo presentan me hace sentir que esto es muy diferente de Ab1
. Y de hecho, resulta ser. Usan una pila para manipular el estado de Ab2
y reservan la memoria de Heap para Ab1
. Ab2
muere después de un tiempo (después de terminar de ejecutar).
Además, la forma de definir qué hacer con Ab2
se realiza a través de otra porción de almacenamiento llamada Ab2_Code
y la especificación para Ab1
implica de manera similar Ab1_Code
Yo diría, ¡esto es fantástico! Tengo tanta comodidad que me permite resolver tantos problemas.
Ahora, sigo mirando desde la perspectiva de un profano, así que no me sorprende que haya pasado por el proceso de pensamiento, pero si cuestionas las cosas de arriba hacia abajo, las cosas pueden ser un poco difíciles de poner en perspectiva. ( Sospecho eso es lo que pasó en tu caso )
Por cierto, olvidé mencionar que Ab1
se llama un objeto oficialmente y Ab2
una pila de funciones, mientras que Ab1_Code
es la definición de la clase y Ab2_Code
es el código de definición de la función .
Y es debido a estas diferencias impuestas por el PL, te das cuenta de que son muy diferentes. ( Tu pregunta )
Nota: No tome mi representación de Ab1
/ Object
como una abstracción de almacenamiento larga como una regla o una cosa concreta, sino desde la perspectiva del profano. El lenguaje de programación proporciona mucha más flexibilidad en términos de administración del ciclo de vida de un objeto. Entonces, objeto puede ser desplegado como Ab1
pero puede ser mucho más.
¿Y tiene esto alguna relación con los funtores (objetos de función)?
Tenga en cuenta que la respuesta de la primera parte es válida para muchos lenguajes de programación en general (incluido C ++), esta parte tiene que ver específicamente con C ++ (cuyas especificaciones ha citado). Para que tenga un puntero a una función, también puede tener un puntero a un objeto. Es solo otra construcción de programación que define C ++. Tenga en cuenta que se trata de tener un puntero a Ab1
, Ab2
para manipularlos en lugar de tener otra abstracción distinta para actuar.
Puede leer sobre su definición, uso aquí:
Déjame responder la pregunta en un lenguaje más simple (términos).
¿Qué contiene una función?
Básicamente contiene instrucciones para hacer algo. Mientras se ejecutan las instrucciones, la función puede almacenar y / o usar temporalmente algunos datos, y puede devolver algunos datos.
Aunque las instrucciones se almacenan en alguna parte, esas instrucciones en sí no se consideran objetos.
Entonces, ¿cuáles son los objetos?
En general, los objetos son entidades que contienen datos, que se manipulan / cambian / actualizan por funciones (las instrucciones).
¿Por qué la diferencia?
Porque las computadoras están diseñadas de tal manera que las instrucciones no dependen de los datos.
Para entender esto, pensemos en una calculadora. Hacemos diferentes operaciones matemáticas usando una calculadora. Digamos, si queremos agregar algunos números, proporcionamos los números a la calculadora. Sin importar cuáles sean los números, la calculadora los agregará de la misma manera siguiendo las mismas instrucciones (si el resultado excede la capacidad de la calculadora para almacenar, mostrará un error, pero eso se debe a la limitación de la calculadora para almacenar el resultado (el datos), no debido a sus instrucciones para la adición).
Las computadoras están diseñadas de la misma manera. Es por eso que cuando utiliza una función de biblioteca (por ejemplo qsort()
) en algunos datos que son compatibles con la función, obtiene el mismo resultado que esperaba, y la funcionalidad de la función no cambia si los datos cambian - porque las instrucciones de la función permanecen sin cambios.
Relación entre funcion y funtores
Las funciones son un conjunto de instrucciones; y mientras se ejecutan, se pueden requerir algunos datos temporales para almacenar. En otras palabras, algunos objetos pueden crearse temporalmente al ejecutar la función. Estos objetos temporales son funtores.
Mucha de la diferencia se reduce a los indicadores y direcciones. En C ++ ¹, los punteros a las funciones y los punteros a los objetos son tipos de cosas estrictamente separados.
C ++ requiere que puedas convertir un puntero a cualquier tipo de objeto en un puntero a void
, luego convertirlo de nuevo al tipo original, y el resultado será igual al puntero que comenzaste con². En otras palabras, independientemente de cómo lo hacen, la implementación debe garantizar que la conversión de puntero a objeto tipo a puntero a vacío no tenga pérdidas, así que no importa cuál sea el original, la información que contenga puede ser recreado para que pueda recuperar el mismo puntero que comenzó con la conversión de T*
a void *
y de regreso a T*
.
Sin embargo, eso no es cierto con un puntero a una función: si toma un puntero a una función, la convierte a void *
y luego la convierte de nuevo a un puntero a una función, puede perder algo de información en el proceso. Es posible que no recuperes el puntero original, y eliminar la referencia de lo que obtienes te da un comportamiento indefinido (en resumen, no lo hagas).
Por lo que vale, puede , sin embargo, convertir un puntero a una función en un puntero a un tipo diferente de función, luego convertir ese resultado al tipo original, y se le garantiza que el resultado es el mismo que el que comenzó con.
Aunque no es particularmente relevante para la discusión en cuestión, hay algunas otras diferencias que pueden valer la pena mencionar. Por ejemplo, puede copiar la mayoría de los objetos, pero no puede copiar ninguna función.
En lo que respecta a la relación con los objetos de función: bueno, realmente no hay mucho de uno más allá de un punto: un objeto de función admite sintaxis que se parece a una llamada de función, pero sigue siendo un objeto, no una función. Por lo tanto, un puntero a un objeto de función sigue siendo un puntero a un objeto. Si, por ejemplo, convierte uno en void *
, y luego lo vuelve a convertir al tipo original, aún le garantizamos que recuperará el valor del puntero original (lo que no sería cierto con un puntero a una función).
En cuanto a por qué los punteros a las funciones son (al menos potencialmente) diferentes de punteros a objetos: parte de esto se reduce a los sistemas existentes. Por ejemplo, en MS-DOS (entre otros) había cuatro modelos de memoria completamente separados: pequeño, mediano, compacto y grande. El modelo pequeño usa direcciones de 16 bits para funciones o datos. Medium usó direcciones de 16 bits para datos y direcciones de 20 bits para código. Compacto invertido que (direcciones de 16 bits para código, direcciones de 20 bits para datos). Grandes utilizaban direcciones de 20 bits tanto para código como para datos. Por lo tanto, en modelos compactos o medianos, la conversión de punteros a código y punteros a funciones realmente podría conducir a problemas.
Más recientemente, un buen número de DSP han utilizado buses de memoria completamente separados para el código y para los datos y (al igual que con los modelos de memoria de MS-DOS) a menudo tenían anchos diferentes, convirtiendo entre los dos podría y perdió información.
- Estas reglas particulares vinieron a C ++ desde C, entonces lo mismo es cierto en C, para lo que sea que valga.
- Aunque no se requiere directamente, con la forma en que funcionan las cosas, casi lo mismo ocurre para una conversión del tipo original a un puntero a
char
y viceversa, para lo que sea que valga la pena.