c++ - punteros - ¿Por qué las definiciones de puntero de función funcionan con cualquier número de símbolos ''&'' o asteriscos ''*''?
punteros a cadenas (2)
¿Por qué funcionan los siguientes?
void foo() {
cout << "Foo to you too!/n";
};
int main() {
void (*p1_foo)() = foo;
void (*p2_foo)() = *foo;
void (*p3_foo)() = &foo;
void (*p4_foo)() = *&foo;
void (*p5_foo)() = &*foo;
void (*p6_foo)() = **foo;
void (*p7_foo)() = **********************foo;
(*p1_foo)();
(*p2_foo)();
(*p3_foo)();
(*p4_foo)();
(*p5_foo)();
(*p6_foo)();
(*p7_foo)();
}
Creo que también es útil recordar que C es solo una abstracción para la máquina subyacente y este es uno de los lugares donde se está filtrando esa abstracción.
Desde la perspectiva de la computadora, una función es solo una dirección de memoria que, si se ejecuta, realiza otras instrucciones. Por lo tanto, una función en C se modela como una dirección, lo que probablemente conduce al diseño de que una función es "la misma" que la dirección a la que apunta.
Hay algunas partes de esto que permiten que todas estas combinaciones de operadores funcionen de la misma manera.
La razón fundamental por la que todo esto funciona es que una función (como foo
) se puede convertir implícitamente en un puntero a la función. Esta es la razón por la cual void (*p1_foo)() = foo;
funciona: foo
se convierte implícitamente en un puntero a sí mismo y ese puntero se asigna a p1_foo
.
El unario &
, cuando se aplica a una función, produce un puntero a la función, al igual que la dirección de un objeto cuando se aplica a un objeto. Para los punteros a las funciones ordinarias, siempre es redundante debido a la conversión implícita de puntero a función. En cualquier caso, esta es la razón por la cual void (*p3_foo)() = &foo;
trabajos.
El unario *
, cuando se aplica a un puntero de función, produce la función apuntada a, tal como lo hace el objeto apuntado cuando se aplica a un puntero ordinario a un objeto.
Estas reglas pueden ser combinadas. Considera tu segundo al último ejemplo, **foo
:
- Primero,
foo
se convierte implícitamente en un puntero a sí mismo y el primer*
se aplica a ese puntero de función, produciendo la funciónfoo
nuevamente. - Luego, el resultado se convierte de nuevo implícitamente en un puntero a sí mismo y se aplica el segundo
*
, lo que de nuevo produce la funciónfoo
. - Luego se convierte implícitamente de nuevo en un puntero de función y se asigna a la variable.
Puedes agregar tantos *
s como quieras, el resultado es siempre el mismo. Cuanto más *
s, mejor.
También podemos considerar su quinto ejemplo, &*foo
:
- Primero,
foo
se convierte implícitamente en un puntero a sí mismo; Se aplica el unario*
, produciendofoo
nuevamente. - Luego, el
&
se aplica afoo
, dando un puntero afoo
, que se asigna a la variable.
Sin embargo, el &
solo se puede aplicar a una función, no a una función que se haya convertido en un puntero de función (a menos que, por supuesto, el puntero de función sea una variable, en cuyo caso el resultado es un puntero a un puntero). -a-una-función; por ejemplo, puede agregar a su lista void (**pp_foo)() = &p7_foo;
).
Es por esto que &&foo
no funciona: &foo
no es una función; es un puntero de función que es un valor r. Sin embargo, &*&*&*&*&*&*foo
funcionaría, como lo haría &******&foo
, porque en ambas expresiones la &
siempre se aplica a una función y no a un puntero de función rvalue .
Tenga en cuenta también que no necesita usar el unary *
para realizar la llamada a través del puntero de función; ambos (*p1_foo)();
y (p1_foo)();
tienen el mismo resultado, de nuevo debido a la conversión de puntero de función a función.