2010-02-05 23 views
14

tengo clase con una gran cantidad de funciones de conversión:¿Puedo prohibir llamar a métodos estáticos en instancia de objeto?

class Something { 
    public: 

    string toXml(); 
    string toJson(); 
    ... 

    static Something fromXml(string); // factory 
    static Something fromJson(string); // factory 
    ... 
}; 

Dado que las funciones estáticas pueden ser llamados ejemplo, es fácil escribir código como este:

Something sss; 

... initializing sss ... 

string xml1 = sss.toXml(); 
sss.fromXml(xml1); // does nothing 
string xml2 = sss.toXml(); 
assert(xml1 == xml2); // always true 

por lo que quiero prohibir a llamar fromXXX en objetos, o al menos hacer que hagan algo diferente.

¿Hay alguna manera de hacerlo?

+0

¿No debería el compilador advertir si se está llamando a una función estática en un objeto? Dependiendo de su entorno, ¿quizás puede agregar banderas de #pragma o del compilador para forzar que la advertencia sea un error? – Macke

+0

@Marcus: Eso es válido C++. Si pudiera forzar una advertencia sobre esto, sería suficiente para mí. Pero parece imposible. – Ivan

Respuesta

0

Revise su diseño en su lugar. Divida sus métodos estáticos en una clase separada de SomethingFactory. Esto es solo confuso

+0

Ese podría ser el espacio de nombres de SomethingFactory también. Pero las funciones tienen que ser amigos de la clase Something. El código será más complejo. Si pudiera prohibir confundir la sintaxis de la llamada, sería completamente correcto. – Ivan

+0

@Ivan: si pudieras rediseñar el lenguaje C++ para que tu problema específico fuera trivial, entonces ya no tendrías ningún problema. (Y a veces es la mejor solución.) Sin embargo, es poco probable que el cambio de idioma cumpla con sus requisitos y, por lo tanto, su solución ideal simplemente no es posible en C++. –

+0

@Roger: No estoy seguro de que el estándar de C++ diga directamente que no puedo identificar qué formulario de llamada se utilizó. Si C++ evalúa el "objeto" en la llamada "object.staticMethod()" de todos modos, podría proporcionarlo a la función estática como "this". O haz algo como eso. – Ivan

5

¿Realmente necesitan ser miembros de la clase? La forma obvia de prevenir esto es hacer que sean funciones gratuitas.

+4

En esa nota: http://www.drdobbs.com/cpp/184401197 Habla sobre cómo las funciones libres son mejores para la encapsulación. – Eld

+0

Solo quería mantener el espacio de nombres global limpio: este objeto es visible en todo el mundo en un gran programa. Por supuesto que podría hacer el espacio de nombres "SomethingUtils" para ellos. Pero parecían funciones de "fábrica". Realmente tenía sentido hasta que perdí 2 horas buscando "errores" no existentes. – Ivan

+0

Eld, las funciones gratuitas serán "amigos" con clase de todos modos. El nivel de incapsulación no cambia. – Ivan

3

La norma requiere realmente todos los compiladores compatibles para permitir que la sintaxis en 9.4 [class.static]/2:

Un miembro estático s de la clase X puede ser se refiere a la utilización de la expresión calificado-id X :: s; no es necesario utilizar la sintaxis de acceso de miembro de clase (5.2.5) para hacer referencia a un miembro estático. Un miembro estático puede referirse al uso de la sintaxis de acceso de miembro de clase, en , en cuyo caso se evalúa la expresión de objeto .

Ahora, hay algunas cosas que puede hacer para evitar el peligro, en ningún orden en particular

  • convertirlos en libres funciones no permitir la sintaxis
  • Mejorar la convención de nomenclatura: createFromXml hacer más explícito que es un método de fábrica
  • Convertir el método estático en un método concreto que va a realizar la operación en el objeto, y proporcionar un método externo de la fábrica que va a reutilizar el código.

Desde el punto de vista del diseño, la primera opción tiene la ventaja de desvincular los formatos serializados de la propia clase. Something (por un nombre mejor), representa un objeto con propiedades y operaciones y todas esas cosas OO. Pero en muchos casos Something no está relacionado con el hecho de que se puede serializar para enviar o almacenar en diferentes formatos.

Los usuarios de su clase Something que solo quieren trabajar con XML no necesitan saber siquiera que su objeto se puede serializar a Json. Ninguno de los usuarios de Json o XML se verá afectado si posteriormente agrega una opción de persistencia de base de datos a la clase.

+0

@David: estas funciones no son para la serialización, sino para la conversión. Cualquiera que use ese encabezado querrá convertir algo a una forma más útil. Podría ser JSON, XML u otro objeto. Mantener todo esto en un encabezado parece razonable. El estándar permite ambos formularios de llamadas. Pero no dice que no puedo identificar la forma que se usó. Por ejemplo, podría establecer "this" a NULL en la llamada "Type :: method", pero al objeto real en la llamada "object.method". Aún así, me pregunto por qué está permitida la sintaxis de "object.method". Es confuso, especialmente en el formulario "this-> staticMethod()" que se requiere en las plantillas. – Ivan

+0

'this->' rara vez se requiere, incluso en plantillas. A veces es más conveniente que usar un nombre calificado ('Nombre :: miembro'), como cuando se accede a un miembro heredado de una clase base que depende de un parámetro de plantilla (y, por lo tanto, el miembro es un nombre dependiente, por lo que no se puede solo nombrarlo solo). –

+0

@Roger: es una sintaxis diferente. El nombre calificado se romperá si renombra la clase o la mueve a otro espacio de nombre, y "this->" no lo hará. Y es confuso de todos modos. ¿Por qué C++ permite la sintaxis "object.staticMethod()"? Puede usar "Type :: staticMethod()" en su lugar con la función trivial helper de plantilla. – Ivan

-1

¿Qué tal hacer que sus miembros estáticos sean privados?

Si es necesario tener funciones miembro que son estáticas esto puede ser una manera de resolver esto.

¿Por qué tiene la función miembro estática? ¿Necesitan acceso a otra cosa en la clase?De lo contrario, podría hacer que las funciones libres no estén en el encabezado con Something, pero en otro encabezado en un espacio de nombres separado.

+0

Ser privado no funcionaría aquí, y realmente no tiene nada que ver con eso. Son métodos de fábrica, que es otra forma de decir que son constructores especiales ("constructores con nombre"). –

+0

Esta clase solo tiene funciones toXXX/fromXXX y apunta a la implementación. Mover las funciones hará que esta clase esté casi vacía. Y todavía tienen que ser amigos. Sin estas funciones Algo es completamente inútil. No creo que deberían estar en un archivo de encabezado separado. – Ivan

Cuestiones relacionadas