2010-05-05 23 views
9

¿Es esta la manera correcta de usar una variable estática const? En mi clase de nivel superior (Forma)const estático doble en C++

#ifndef SHAPE_H 
#define SHAPE_H 

class Shape 
{ 
public: 

    static const double pi; 
private: 
    double originX; 
    double originY; 
}; 

const double Shape::pi = 3.14159265; 

#endif 

Y más tarde en una clase que se extiende Forma, yo uso Forma :: pi. Obtengo un error de enlazador. Moví el const double Shape :: pi = 3.14 ... al archivo Shape.cpp y mi programa luego compila. ¿Por qué sucede eso? Gracias.

Respuesta

10

Debido const double Shape::pi = 3.14159265; es la definición de Shape::pi y C++ sólo permite una única definición de un símbolo (llamado el one-definition-rule la que se puede ver en su forma siglas ODR). Cuando la definición está en el archivo de encabezado, cada unidad de traducción obtiene su propia definición que rompe esa regla.

Al moverlo al archivo de origen, obtiene solo una definición.

+0

Tengo el mismo problema. El problema es, si esto es una biblioteca, y quiero que mi usuario vea el valor de Shape :: pi en el archivo .h, pero no el contenido de cpp (es decir, otra definición de función). ¿Que debería hacer? –

3

Sucede porque no puede definir Shape :: pi más de una vez. Se define una vez cuando incluyes Shape.h en Shape.cpp, y luego cada vez que usas Shape.h en otro archivo cpp. Cuando vaya a vincular el programa, el vinculador se descartará debido a múltiples definiciones.

1

La línea const double Shape::pi = 3.14159265; debe estar en su archivo Shape.cpp. El archivo de encabezado es para declarar las variables. Solo puede definir una variable una vez, por lo tanto, debe hacerse en el .cpp. El archivo de encabezado dice cómo usar estas variables y funciones, el archivo cpp dice qué hacer.

12

Los miembros de datos flotantes estáticos deben definirse e inicializarse en un archivo de origen. La regla de una definición prohíbe una definición fuera del bloque class {} en el encabezado, y solo se pueden inicializar los miembros de datos integrales dentro del bloque class {}.

Esto también es desafortunado porque, al ser un valor algebraico, tener el valor inmediato a mano podría ser bueno para la optimización, en lugar de cargarlo desde una variable global. (Sin embargo, es probable que la diferencia sea inconsecuente).

¡Sin embargo, existe una solución!

class Shape 
{ 
public: 
    static double pi() 
     { return 3.14159265; } 

private: 
    double originX; 
    double originY; 
}; 

definiciones función en línea, incluyendo los estáticos, están permitidos dentro del bloque class{}.

Además, recomiendo usar M_PI de <math.h>, que también debería obtener de <cmath>.

+0

adicionalmente: las plantillas tienen un vínculo diferente, por lo que podría usar una plantilla para hacer que la definición sea visible – justin

+2

@Justin: No creo que 'template' tenga nada aquí, excepto complicación adicional. – Potatoswatter

+0

una plantilla puede complicar las cosas, pero potencialmente puede comprar una excepción a la regla de una definición para "miembro de datos estáticos de una plantilla de clase" (entre otras excepciones ODR). Ver 3.2/5 y 14.5.1.3 del Estándar C++. –

1

Para los tipos de datos primitivos (como int, double, pero no char []) también puede definir la constante dentro de la definición de clase en el archivo de cabecera, por ejemplo .:

class Shape 
{ 
public: 
    static const double pi = 3.14159265; 

private: 
    double originX; 
    double originY; 
}; 

Esto permitirá una mejor optimización del compilador.

Editar: Como Dennis señaló a continuación, esto solo se permite para los tipos integrales y no para los tipos de datos dobles o float (sin embargo, algunos compiladores lo permitirán).

+1

Solo puede hacer esto para los tipos integral y enum. Los tipos de punto flotante no están permitidos. –

+0

@Dennis: ¡Ups! ¡Tienes razón! Fui engañado por el compilador (gcc e icc permitieron que static const double se inicializara dentro de la clase) ... – Oliver

5

Si usted tiene una manera de agregar C++0x bandera para su compilador, que le ha sido capaz de hacer:

ifndef SHAPE_H 
#define SHAPE_H 

class Shape 
{ 
public: 

    static constexpr double pi = 3.14159265; 
private: 
    double originX; 
    double originY; 
}; 

#endif 

En C++0x que son capaces de utilizar expresiones const de tipos distintos de los integrales. Esto le permite declarar y definir en su lugar su variable constante.

0

Implemente una función que devuelve el índice de un valor a la lista, si existe. De lo contrario, devuelve -1 si no hay ningún valor. Si el mismo valor existe más de una vez en la lista, el primer valor se borrará de la parte inferior.

public static intfindFromLast (List <Double> l, double value) {///…}