tipos - Definir variables constantes en el encabezado de C++.
variables y constantes en c++ (6)
Un programa en el que estoy trabajando tiene muchas constantes que se aplican en todas las clases. Quiero hacer un archivo de encabezado "Constantes.h" y poder declarar todas las constantes relevantes. Luego, en mis otras clases, solo puedo incluir #include "Constants.h
.
Conseguí que funcionara bien usando la #ifndef
... #define ...
Sin embargo, preferiría usar la forma constante de constantes. No estoy muy seguro de cómo hacerlo.
En lugar de hacer un montón de variables globales, puede considerar crear una clase que tenga un montón de constantes estáticas públicas. Todavía es global, pero de esta manera está envuelto en una clase para que sepas de dónde viene la constante y que se supone que es una constante.
Constantes.h
#ifndef CONSTANTS_H
#define CONSTANTS_H
class GlobalConstants {
public:
static const int myConstant;
static const int myOtherConstant;
};
#endif
Constantes.cpp
#include "Constants.h"
const int GlobalConstants::myConstant = 1;
const int GlobalConstants::myOtherConstant = 3;
Entonces puedes usar esto así:
#include "Constants.h"
void foo() {
int foo = GlobalConstants::myConstant;
}
Me gusta el espacio de nombres mejor para este tipo de propósito.
Opción 1 :
#ifndef MYLIB_CONSTANTS_H
#define MYLIB_CONSTANTS_H
// File Name : LibConstants.hpp Purpose : Global Constants for Lib Utils
namespace LibConstants
{
const int CurlTimeOut = 0xFF; // Just some example
...
}
#endif
// source.cpp
#include <LibConstants.hpp>
int value = LibConstants::CurlTimeOut;
Opcion 2 :
#ifndef MYLIB_CONSTANTS_H
#define MYLIB_CONSTANTS_H
// File Name : LibConstants.hpp Purpose : Global Constants for Lib Utils
namespace CurlConstants
{
const int CurlTimeOut = 0xFF; // Just some example
...
}
namespace MySQLConstants
{
const int DBPoolSize = 0xFF; // Just some example
...
}
#endif
// source.cpp
#include <LibConstants.hpp>
int value = CurlConstants::CurlTimeOut;
int val2 = MySQLConstants::DBPoolSize;
Y nunca usaría una clase para mantener este tipo de variables constantes de HardCoded.
No puede usar, por ejemplo, const int
en un archivo de encabezado, si está incluido en varios archivos de origen. Esto se debe a que las variables se definirán en todos los archivos de origen (unidades de traducción técnicamente hablando). Debe tener un archivo fuente especial, Constants.cpp
que realmente define las variables, y luego tener las variables declaradas como extern
en el archivo de encabezado.
Algo así como este archivo de cabecera:
// Protect against multiple inclusions in the same source file
#ifndef CONSTANTS_H
#define CONSTANTS_H
extern const int CONSTANT_1;
#endif
Y esto en un archivo fuente:
const int CONSTANT_1 = 123;
Parece que la respuesta de bames53 se puede extender a la definición de valores constantes enteros y no enteros en el espacio de nombres y en las declaraciones de clase, incluso si se incluyen en varios archivos de origen. No es necesario colocar las declaraciones en un archivo de cabecera, sino las definiciones en un archivo de origen. El siguiente ejemplo funciona para Microsoft Visual Studio 2015, para z / OS V2.2 XL C / C ++ en OS / 390 y para g ++ (GCC) 8.1.1 20180502 en GNU / Linux 4.16.14 (Fedora 28). Tenga en cuenta que las constantes se declaran / definen en un solo archivo de encabezado que se incluye en varios archivos de origen.
En foo.cc:
#include <cstdio> // for puts
#include "messages.hh"
#include "bar.hh"
#include "zoo.hh"
int main(int argc, const char* argv[])
{
puts("Hello!");
bar();
zoo();
puts(Message::third);
return 0;
}
En mensajes.hh:
#ifndef MESSAGES_HH
#define MESSAGES_HH
namespace Message {
char const * const first = "Yes, this is the first message!";
char const * const second = "This is the second message.";
char const * const third = "Message #3.";
};
#endif
En bar.cc:
#include "messages.hh"
#include <cstdio>
void bar(void)
{
puts("Wow!");
printf("bar: %s/n", Message::first);
}
En zoo.cc:
#include <cstdio>
#include "messages.hh"
void zoo(void)
{
printf("zoo: %s/n", Message::second);
}
En bar.hh:
#ifndef BAR_HH
#define BAR_HH
#include "messages.hh"
void bar(void);
#endif
En zoo.hh:
#ifndef ZOO_HH
#define ZOO_HH
#include "messages.hh"
void zoo(void);
#endif
Esto produce el siguiente resultado:
Hello!
Wow!
bar: Yes, this is the first message!
zoo: This is the second message.
Message #3.
El tipo de datos char const * const
significa un puntero constante a una matriz de caracteres constantes. La primera const
es necesaria porque (según g ++) "ISO C ++ prohíbe convertir una constante de cadena a ''char *''". La segunda const
es necesaria para evitar errores de enlace debido a las múltiples definiciones de las constantes (entonces no lo suficientemente constantes). Es posible que su compilador no se queje si omite una o ambas const
, pero entonces el código fuente es menos portátil.
Simplemente podría definir una serie de const ints
en un archivo de encabezado:
// Constants.h
#if !defined(MYLIB_CONSTANTS_H)
#define MYLIB_CONSTANTS_H 1
const int a = 100;
const int b = 0x7f;
#endif
Esto funciona porque en C ++ un nombre en el ámbito del espacio de nombres (incluido el espacio de nombres global) que se declara explícitamente const y no se declara externamente explícitamente tiene vinculación interna, por lo que estas variables no causarán símbolos duplicados cuando vincule unidades de traducción. Alternativamente, podría declarar explícitamente las constantes como estáticas.
static const int a = 100;
static const int b = 0x7f;
Esto es más compatible con C y más legible para las personas que pueden no estar familiarizadas con las reglas de enlace de C ++.
Si todas las constantes son ints, entonces otro método que podría usar es declarar los identificadores como enumeraciones.
enum mylib_constants {
a = 100;
b = 0x7f;
};
Todos estos métodos usan solo un encabezado y permiten que los nombres declarados se usen como constantes de tiempo de compilación. El uso de la extern const int
y un archivo de implementación separado evita que los nombres se utilicen como constantes de tiempo de compilación.
Tenga en cuenta que la regla que hace que ciertas constantes implícitamente se vinculen internamente se aplica a los punteros, exactamente como constantes de otros tipos. Sin embargo, lo complicado es que marcar un puntero como const
requiere una sintaxis un poco diferente que la mayoría de la gente usa para hacer constantes de variables de otros tipos. Necesitas hacer:
int * const ptr;
para hacer un puntero constante, para que la regla se aplique a ella.
También tenga en cuenta que esta es una razón por la que prefiero poner const
después del tipo: int const
lugar de const int
. También puse el *
junto a la variable: es decir, int *ptr;
en lugar de int* ptr;
.
Me gusta hacer este tipo de cosas porque reflejan el caso general de cómo funciona realmente C ++. Las alternativas ( const int
, int* p
) son especiales para facilitar la lectura de algunas cosas simples. El problema es que cuando se sale de esos casos simples, las alternativas de caja especial se vuelven activamente engañosas.
Entonces, aunque los ejemplos anteriores muestran el uso común de const
, en realidad recomendaría que las personas los escriban así:
int const a = 100;
int const b = 0x7f;
y
static int const a = 100;
static int const b = 0x7f;
El proyecto estándar de C ++ 17 en const
implica static
Esta es la cita de lo que se mencionó en: https://.com/a/12043198/895245
C ++ 17 n4659 borrador estándar 6.5 "Programa y vinculación":
3 Un nombre que tenga un ámbito de espacio de nombres (6.3.6) tiene un enlace interno si es el nombre de
- (3.1) - una variable, función o plantilla de función que se declara explícitamente como estática; o,
- (3.2) - una variable no en línea de tipo cualificado por const no volátil que no se declara explícitamente como externamente ni se declaró anteriormente que tiene un enlace externo; o
- (3.3) - un miembro de datos de una unión anónima.
constexpr
Es probable que desee utilizar constexpr
para este caso de uso simple, ya que también se podría usar en contextos como plantillas. Vea también: Diferencia entre `constexpr` y` const` .