poo - que es un objeto en c++
Definición de la clase base de llamada de la función miembro virtual con puntero a función (6)
Quiero llamar a la implementación de la clase base de una función virtual utilizando un puntero a función miembro.
class Base {
public:
virtual void func() { cout << "base" << endl; }
};
class Derived: public Base {
public:
void func() { cout << "derived" << endl; }
void callFunc()
{
void (Base::*fp)() = &Base::func;
(this->*fp)(); // Derived::func will be called.
// In my application I store the pointer for later use,
// so I can''t simply do Base::func().
}
};
En el código anterior, la implementación de la clase derivada de func se llamará desde callFunc. ¿Hay alguna manera de guardar un puntero de función miembro que apunte a Base :: func, o tendré que usar el using
de alguna manera?
En mi aplicación real, uso boost :: bind para crear un objeto boost :: function en callFunc que luego uso para llamar a func desde otra parte de mi programa. Entonces, si boost :: bind o boost :: function tienen alguna forma de solucionar este problema, eso también ayudaría.
¿Hay alguna razón específica para hacer esto a través de un puntero de función?
Deberías poder simplemente escribir:
Base::func();
para llamar a la implementación de la clase base.
¿Qué pasa con esto?
(Base(*this).*fp)();
Ahora, si está satisfecho con eso, surge la pregunta de por qué incluso está usando un puntero de función en primer lugar. Creo que un poco más de contexto podría ayudar.
Además de lo que dice Quark, una observación más general es que debe usar una implementación de señal / ranura en lugar de un puntero de función simple. Boost tiene uno, hay libsigc y un montón de otros.
Cuando llama a un método virtual a través de una referencia o un puntero, siempre activará el mecanismo de llamada virtual que encuentre el tipo más derivado.
Lo mejor que puedes hacer es agregar una función alternativa que no sea virtual.
Lo que estás tratando de hacer, lamentablemente, no es posible. Las funciones de puntero a miembro están diseñadas para mantener la virtualidad de la función apuntada a.
Su problema es que un puntero de función miembro no es exactamente lo mismo que un puntero de función simple. En realidad no es solo un puntero, sino una estructura considerablemente más compleja , que varía en sus detalles a nivel de la implementación del compilador. Cuando lo invocas a través de la sintaxis (this->*fp)()
, en realidad lo llamas al objeto original, lo que provoca el despacho de la función virtual.
Una cosa que podría funcionar es convertirlo en un tipo de puntero que no sea de método. Esto es un poco chirriante pero creo que debería funcionar. Aún necesita pasar una Base *
pero lo hace explícitamente y el envío de la función virtual se pasa por alto:
typedef void BasePointer(Base*);
void callFunc()
{
BasePointer fp = (BasePointer *)&Base::func;
fp(this);
}
Actualización: Ok, no, no puedes hacerlo de esa manera. Es ilegal, y no estaría seguro si fuera legal. Las preguntas frecuentes de C ++ tienen más información sobre esto . Pero saber eso no resuelve tu problema. El problema es que, puntero a objeto o puntero a miembro, si desea llamar a Base::func
través de un puntero de Base
, el objeto al que apunta también debe ser una Base
. Si puede organizar eso, entonces puede usar un puntero de función miembro.
Aquí hay otro pensamiento, no bonito, pero al menos viable. Proporcione una función en Derived
, no virtual, que llame explícitamente a Base::func
. Señala eso en lugar de eso. No se escalará si necesita hacer esto en el caso general de muchas variantes diferentes de func
y callFunc
pero funcionará bien para un método.