2010-12-03 26 views
5

Considere el siguiente código.Llamar a una función virtual estáticamente a través de un puntero a la función

#include <iostream> 
#include <memory> 

struct A { 
    A() {} 
    virtual void f() { 
    std::cout << "A::f" << std::endl; 
    } 
private: 
    A(const A&); 
}; 

struct B : public A { 
    virtual void f() { 
    std::cout << "B::f" << std::endl; 
    call(&A::f); 
    } 
private: 
    void call(void (A::*aMethod)()) { 
    // ... 
    (static_cast<A&>(*this).*aMethod)(); 
    //(static_cast<A>(*this).*aMethod)(); -> not allowed to copy! 
    // ... 
    } 
}; 

void main() { 
    std::auto_ptr<B> b (new B); 
    b->f(); 
} 

Este código llama de forma recursiva el mismo método B::f hasta que se agote la pila, mientras que me gustaría que el método call llamar A::f. Es decir, se debe llamar de forma estática, ya que normalmente pasaría si hubiera escrito simplemente:

struct B : public A { 
    virtual void f() { 
    std::cout << "B::f" << std::endl; 
    // ... 
    A::f(); 
    // ... 
    } 
}; 

La razón por la que quieren tener el método call es factorizar algún código antes y después de la 'llamada estática' que es común a varios métodos con la misma firma como f ...

¿Cómo puedo estáticamente llamar a una función virtual decidió en tiempo de ejecución?

+0

En 'B :: F', ¿por qué tiene que llamar a la función a través de' call' y un puntero de función? ¿Por qué no puedes hacer 'A :: f();'? (Refactorizar el código "antes" y "después" en algunas funciones comunes o en una clase común.) –

+0

Eso es probablemente lo que tendré que hacer ... El método 'llamada' estaba aquí para factorizar el código, pero tenía no di cuenta de que no sería capaz de utilizarlo como tenía la intención de ... –

Respuesta

4

que se espera. La expresión del objeto es una Referencia a la clase Base A y, por lo tanto, el mecanismo de función virtual (vinculación dinámica) se activa cuando A :: f es virtual.

Sólo el operador puede supperess :: mecanismo de llamada a una función virtual.

$ 10,3/12- "calificación explícita con el operador alcance (5.1) suprime el mecanismo de llamada virtual."

+0

y parece que no puedo usar el operador alcance aquí: sería calificar el nombre del puntero, no la función señaló que ... Sí –

+0

, AFAICT, tendrá que ir con A :: f – Chubsdad

1

Su anulación se resuelve cuando toma el puntero, por lo que lo que desea aquí no es posible de esta manera. Lo mejor que puede hacer es un contenedor que llame a su función, ya sea algo externo o una función no virtual que llame a su función. Si tiene características de C++ 0x, podría usar una lambda que es la solución más limpia de la OMI.

Es posible que desee replantearse la forma en que realiza las funciones previas/posteriores como otra forma de abordar su problema: pueden implementarse sobrecargando el operador "->".

+0

Desafortunadamente, el operador de sobrecarga-> no es aplicable en el caso real porque se aplicaría a cualquier método llamado, no solo para fy los otros que son similares ... Pero gracias de todos modos ... –

+0

Sí, eso suele ser un problema. Sin embargo, tal vez pueda refactorizar su código para poner simplemente esos métodos en una clase de interfaz separada. O simplemente aplicar el operador de envoltura en la llamada in situ de sus funciones virtuales como de llamadas (myObject) -> f(); – ltjax

+0

En realidad, ni siquiera necesita sobrecargar -> para la última idea. Basta con implementar ctor y dtor de tipo "Llamar". – ltjax

Cuestiones relacionadas