virtuales punteros poo objetos herencia funciones ejemplo codigo c++ virtual-functions member-function-pointers

poo - punteros c++



C++: ¿Puntero a versión monomórfica de función miembro virtual? (3)

En C ++, es posible obtener un puntero a una función miembro (no estática) de una clase y luego invocarla en un objeto. Si la función era virtual, la llamada se envía dinámicamente según el tipo dinámico del objeto. También es posible (sin usar un puntero de miembro) llamar funciones de miembros virtuales de objetos monomorfamente, proporcionando explícitamente el ámbito que contiene la versión a usar. El siguiente código demuestra esto:

#include <iostream> using std::cout; using std::endl; struct Foo { virtual void foo() { cout << 1 << endl; } }; struct Foo2: public Foo { virtual void foo() { cout << 2 << endl; } }; int main( int, char** ) { Foo *foo = new Foo2; void (Foo::*foo_pointer)() = &Foo::foo; foo->foo(); // prints 2 foo->Foo::foo(); // prints 1 (foo->*foo_pointer)(); // prints 2 }

Lo que me gustaría hacer es combinar los dos y obtener un puntero a la versión monomórfica de una función miembro; es decir, quiero un puntero a Foo :: foo, que siempre llama a la versión de clase base de foo e imprime 1, incluso si se invoca en un Foo2. Sin embargo, no he podido encontrar una manera de hacer esto. ¿Es posible?

(Aparte de la tediosa forma manual de escribir una nueva función no virtual que realiza la llamada monomórfica y luego obtiene un puntero a eso).


En otras palabras: quieres hacer trampa.

No, no es posible porque así es como funciona el polimorfismo en combinación con el puntero al método miembro.


Es posible en GCC , pero la forma en que está documentado en la sección de extensiones de lenguaje C ++ sugiere que no hay una forma portátil de hacerlo.

Puedes hacer dos cosas:

  1. Si controla la clase, cree una función no virtual y una envoltura virtual para ella y cuando sepa que no necesita un envío virtual, simplemente tome la dirección de la no virtual.
  2. Si no lo hace, cree un functor de plantilla que mantendrá el puntero del miembro y realice la llamada de alcance explícita.

Para elaborar con un ejemplo de código para una función de envoltorio (y, a pesar del hecho, ¡el OP quiso evitar este método!) Ya que en muchos casos esta es la solución pragmáticamente preferible:

#include <iostream> using std::cout; using std::endl; struct Foo { virtual void foo() { cout << 1 << endl; } }; struct Foo2: public Foo { virtual void foo() { cout << 2 << endl; } }; void monomorphicFooFoo( Foo * f ) { f->Foo::foo(); } int main() { Foo *foo = new Foo2; void (*baseFoo)( Foo * ) = &monomorphicFooFoo; baseFoo( foo ); // Prints 1 }