2012-06-20 9 views
13

Parece que std::cout no puede imprimir la dirección de la función miembro, por ejemplo:Cómo imprimir dirección de función miembro de C++

#include <iostream> 

using std::cout; 
using std::endl; 

class TestClass 
{ 
    void MyFunc(void); 

public: 
    void PrintMyFuncAddress(void); 
}; 

void TestClass::MyFunc(void) 
{ 
    return; 
} 

void TestClass::PrintMyFuncAddress(void) 
{ 
    printf("%p\n", &TestClass::MyFunc); 
    cout << &TestClass::MyFunc << endl; 
} 

int main(void) 
{ 
    TestClass a; 

    a.PrintMyFuncAddress(); 

    return EXIT_SUCCESS; 
} 

el resultado es algo como esto:

003111DB 
1 

¿Cómo puedo imprimir la dirección MyFunc usando std::cout?

Respuesta

16

No creo que haya ningún medio proporcionado por el idioma para hacer esto. Hay sobrecargas para operator << para las transmisiones para imprimir punteros normales void*, pero los punteros de función del miembro no son convertibles a void* s. Esto es todo específico de la implementación, pero típicamente los punteros de función de miembro se implementan como un par de valores: un indicador que indica si la función miembro es o no virtual y algunos datos adicionales. Si la función no es virtual, esa información adicional suele ser la dirección real de la función miembro. Si la función es una función virtual, esa información adicional probablemente contenga datos sobre cómo indexarla en la tabla de funciones virtuales para encontrar la función a llamar dado el objeto receptor.

En general, creo que esto significa que es imposible imprimir las direcciones de las funciones miembro sin invocar un comportamiento indefinido. Probablemente tengas que usar algún truco específico del compilador para lograr este efecto.

Espero que esto ayude!

+0

Para algunas estadísticas interesantes sobre los tamaños y las implementaciones de punteros a miembro-funciones en diversos compiladores, vea la tabla al final de [este artículo] (http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible). Sin embargo, dado que ese artículo es algo anticuado (escrito en 2005), es probable que las cifras ya no sean precisas, pero dan una idea aproximada. –

4

Una forma de hacerlo es (no estoy seguro de que es portátil):

void TestClass::PrintMyFuncAddress(void) 
{ 
    void (TestClass::* ptrtofn)() = &TestClass::MyFunc; 
    cout << (void*&)ptrtofn<< endl; 
} 

ejemplo de trabajo: http://ideone.com/1SmjW

+3

Ese programa demuestra muy poco. Ese molde de estilo C es un 'reinterpret_cast' que generalmente solo reinterpreta la memoria como el tipo de destino. En este caso, utilizará los primeros bytes 'sizeof (void *)' almacenados en el puntero al miembro como si fuera 'void *', pero si comprueba los tamaños de ambos tipos verá que difieren (puntero) para miembro es más grande). –

+0

@ DavidRodríguez-dribeas: Pero debería (probablemente) imprimir el mismo valor que el "% p" de printf(). Probablemente ambos estén equivocados (suponiendo que los punteros de los miembros son más grandes que los punteros normales (por lo general son ciertos)). –

13

me gustaría añadir a las otras respuestas, que la razón por la que está imprimiendo '1' en lugar de una dirección, es por alguna razón que el compilador fuerza su puntero a un booleano, por lo que realmente llama al ostream& operator<< (bool val);

Esto parece no estar relacionado con la función un miembro f unción.

Usted puede encontrar este tipo de información con el sonido metálico ++ -cc1 -ast-dump:

(ImplicitCastExpr 0x3861dc0 <col:13, col:25> '_Bool' <MemberPointerToBoolean> 
    (UnaryOperator 0x3861940 <col:13, col:25> 'void (class TestClass::*)(void)' prefix '&' 
     (DeclRefExpr 0x38618d0 <col:14, col:25> 'void (void)' CXXMethod 0x3861500 'MyFunc' 'void (void)'))))) 
+0

Los números de línea se cambian. –

+1

gracias por señalar la opción de volcado de sintaxis. – fduff

+0

De nada ... ;-) –

1

Los punteros a funciones miembro necesitan memoria, también. También tienen un tamaño. Entonces, ¿qué impresión de la memoria del puntero:

template<typename R, typename T, typename... Args> 
std::string to_string(R (T::*func)(Args...)) 
{ 
    union PtrUnion 
    { 
     R(T::*f)(Args...); 
     std::array<unsigned char, sizeof(func)> buf; 
    }; 
    PtrUnion u; 
    u.f = func; 

    std::ostringstream os; 

    os << std::hex << std::setfill('0'); 
    for (auto c : u.buf) 
     os << std::setw(2) << (unsigned)c; 

    return os.str(); 
} 

Usted puede usarlo de esta manera:

class TestClass 
{ 
    void foo(); 
}; 

... 

std::cout << to_string(&TestClass::foo) << std::endl; 
Cuestiones relacionadas