2008-11-28 19 views
30

Aquí hay un pequeño programa de prueba:C++ estática miembro de llamada a un método de instancia de clase

En VS2008 + SP1 (VC9) que compila bien: "! PRUEBA DE TI" la consola solo se vea.

Por lo que sé, los métodos de miembros estáticos no se deben invocar en el objeto instanciado.

  1. ¿No funciona? ¿Este código es correcto desde el punto de vista estándar?
  2. Si es correcto, ¿por qué es eso? No puedo encontrar por qué estaría permitido, o tal vez es para ayudar a usar el método "estático o no" en las plantillas.
+0

¿Qué pasa con el t mvc ag? – Kiril

+0

Reparado: podría haber mezclado con msvc en ese momento, estaba pensando que podría ser un problema de compilación. – Klaim

Respuesta

54

La norma establece que no es necesario llamar al método a través de una instancia, eso no significa que no pueda hacerlo. Hay incluso un ejemplo donde se utiliza:

C++ 03, 9.4 miembros estáticos

Un miembro estático s de la clase X pueden ser referidos a la utilización de la expresión calificado-id X :: s ; es no es necesario usar la sintaxis de acceso de miembro de clase (5.2.5) para referirse a a un miembro estático. Se puede hacer referencia a un miembro estático utilizando la sintaxis de acceso de miembro de clase, en la que caso en el que se evalúa la expresión de objeto es .

class process { 
public: 
    static void reschedule(); 
}; 

process& g(); 

void f() 
{ 
    process::reschedule(); // OK: no object necessary    
    g().reschedule(); // g() is called 
} 
+0

Wow, nunca supe esto. Supongo que la función que se llama se basa solo en el tipo de tiempo de compilación (no en el tipo de tiempo de ejecución) de la expresión? –

+0

@SethCarnegie: Sí, utiliza el tipo de tiempo de compilación del objeto (o referencia del mismo), no se puede obtener el envío dinámico a los métodos de miembros estáticos. –

+0

Eso es muy malo. +1 –

2

métodos estáticos se pueden llamar también utilizando un objeto de la clase, al igual que se puede hacer en Java. Sin embargo, no deberías hacer esto. Utilice el operador alcance como Test::DoCrash(); Tal vez usted piensa de espacios de nombres:

namespace Test { 
    void DoCrash() { 
     std::cout << "Crashed!!" << std::endl; 
    } 
}; 

que sólo se puede llamar desde fuera Test::DoCrash(); ese espacio de nombres si la función no ha sido importada de manera explícita el uso de un using directive/declaration en el ámbito de la persona que llama.

+2

Sí, sé que debo hacer esto, es por eso que pregunto por qué la otra manera (llamar como un miembro) está permitida/no prohibida. :) – Klaim

8

funciones estáticas Indiferente necesitan un objeto instanciado para ser llamado, por lo

k.DoCrash(); 

se comporta exactamente igual que

Test::DoCrash(); 

usando el operador de resolución de ámbito (::) para determinar la función estática dentro de la clase.

Observe que en ambos casos el compilador no coloca el puntero this en la pila, ya que la función estática no lo necesita.

+1

Prefiero decir _pass 'this' puntero como un parámetro_ en lugar de _ponerlo en la pila_. La manera real está sujeta a la convención de llamadas de la plataforma en particular. Sin embargo, +1 por mencionar esta característica de métodos estáticos. – Melebius

+0

Hay una diferencia: en 'k.DoCrash()', se evalúa el prefijo 'k'. Si 'k' es solo un nombre de objeto, eso probablemente no importe, pero podría ser una llamada a función o alguna otra expresión con efectos secundarios:' func(). DoCrash() ' –

3

2) Si es correcto, ¿por qué es eso? No puedo encontrar por qué estaría permitido, o tal vez es para ayudar a usar el método "estático o no" en las plantillas.

Se es potencialmente útil en varios escenarios:

  • [el 'método 'estática o no' en las plantillas' que ha sugerido:] cuando muchos tipos podrían haber sido especificada a una plantilla, y la plantilla entonces quiere invocar al miembro: los tipos que proporcionan una función estática se pueden llamar usando la misma notación que una función miembro: el primero puede ser más eficiente (no this puntero para pasar/enlazar), mientras que el último permite polimórficos (virtual) envío y uso de los datos de los miembros

  • minimizando el mantenimiento del código

    • si una función evoluciona de la necesidad de datos específicos de la instancia a no necesitarlo - y por lo tanto se hace static para permitir el fácil uso sin necesidad de instancia y evitar el uso accidental de datos de instancia - todo los puntos de uso del cliente existente no necesitan ser actualizados labouriously

    • si el tipo de cambió el var.f() invocación sigue utilizando la función del tipo var, mientras que Type::f() pueden necesitar corrección manual

  • cuando se tiene una expresión o función de llamada de devolver un valor y desea invocar la static función (potencial o siempre), la notación . puede prevenir que tener que utilizar decltype o una plantilla de apoyo para conseguir el acceso a la tipo, sólo para que pueda utilizar la notación ::

  • a veces el nombre de la variable es mucho más corto, más conveniente, o nombrado en un auto-documentación de forma más

+1

En el compilador de MSVC 2013 al menos, llamando los métodos estáticos a través de una instancia funcionan, pero generan una advertencia del compilador sobre una variable sin referencia si la variable no se usa para nada más que llamar a un método estático. – abelenky

Cuestiones relacionadas