todas - ¿Dónde colocar el valor del parámetro predeterminado en C++?
tipos de funciones en c (10)
Esta pregunta ya tiene una respuesta aquí:
- Valor por defecto del parámetro función 4 respuestas
¿Cuál es el lugar para el valor de parámetro predeterminado? ¿Solo en la definición de función, o declaración, o en ambos lugares?
Añadiendo un punto más. Las declaraciones de funciones con argumentos predeterminados deben ordenarse de derecha a izquierda y de arriba a abajo .
Por ejemplo, en la siguiente declaración de función, si cambia el orden de declaración, el compilador le da un error de parámetro predeterminado faltante. Razón por la que el compilador le permite separar la declaración de función con el argumento predeterminado dentro del mismo ámbito, pero debe estar en orden de DERECHA a IZQUIERDA (argumentos predeterminados) y de ARRIBA a ABAJO (orden del argumento predeterminado de declaración de función).
//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK
int main() {
function("Using only one Default Argument", false, true);
function("Using Two Default Arguments", false);
function("Using Three Default Arguments");
return 0;
}
//definition
void function(char const *msg, bool three, bool two, bool one ) {
std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}
Aunque este es un hilo "antiguo", todavía me gustaría agregarle lo siguiente:
He experimentado el siguiente caso:
- En el archivo de cabecera de una clase, tuve
int SetI2cSlaveAddress( UCHAR addr, bool force );
- En el archivo fuente de esa clase, tuve
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false ) { ... }
Como se puede ver, había puesto el valor predeterminado del parámetro "forzar" en el archivo fuente de la clase, no en el archivo de encabezado de la clase.
Luego usé esa función en una clase derivada de la siguiente manera (la clase derivada heredó la clase base de manera pública):
SetI2cSlaveAddress( addr );
asumiendo que tomaría el parámetro "force" como "falso" ''por supuesto''.
Sin embargo, el compilador ( puesto en modo c ++ 11 ) se quejó y me dio el siguiente error de compilación:
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function ''void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)'':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to ''CMax6956Io::SetI2cSlaveAddress(unsigned char&)''
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2
Pero cuando agregué el parámetro predeterminado en el archivo de encabezado de la clase base:
int SetI2cSlaveAddress( UCHAR addr, bool force = false );
y lo eliminó del archivo fuente de la clase base:
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )
entonces el compilador estuvo feliz y todo el código funcionó como se esperaba (¡podría dar uno o dos parámetros a la función SetI2cSlaveAddress()
)!
Por lo tanto, no solo para el usuario de una clase es importante poner el valor predeterminado de un parámetro en el archivo de encabezado, también, compilar y funcionalmente, ¡parece ser una necesidad!
Buena pregunta ... Encuentro que los programadores normalmente usan la declaración para declarar los valores predeterminados. He sido retenido de una manera (o advertido) u otro también basado en el compilador
void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
using namespace std;
cout << nVal1 << << nVal2 << endl;
}
El lugar más útil está en la declaración (.h) para que todos los usuarios la vean.
A algunas personas también les gusta agregar los valores predeterminados en la implementación (como comentario):
void foo(int x = 42,
int y = 21);
void foo(int x /* = 42 */,
int y /* = 21 */)
{
...
}
Sin embargo, esto significa duplicación y agregará la posibilidad de que el comentario no esté sincronizado con el código (¿qué es peor que el código no comentado? ¡Con comentarios engañosos!).
La declaración es generalmente la más ''útil'', pero eso depende de cómo se quiera usar la clase.
ambos no es valido
Los valores predeterminados de los parámetros deben aparecer en la declaración, ya que eso es lo único que ve la persona que llama.
EDITAR: Como señalan otros, puede tener el argumento de la definición, pero le aconsejaría escribir todo el código como si eso no fuera cierto.
Puede hacerlo en cualquiera de los dos (según el estándar), pero recuerde que si su código está viendo la declaración sin los argumentos predeterminados antes de la definición que contiene el argumento predeterminado, entonces puede aparecer un error de compilación.
Por ejemplo, si incluye el encabezado que contiene la declaración de función sin la lista de argumentos predeterminada, el compilador buscará ese prototipo, ya que desconoce sus valores de argumento predeterminados y, por lo tanto, el prototipo no coincidirá.
Si está definiendo la función con el argumento predeterminado en la definición, incluya ese archivo pero no lo sugeriré.
Puedes hacer cualquiera de las dos cosas, pero nunca ambas. Por lo general, lo hace en la declaración de función y luego todas las personas que llaman pueden usar ese valor predeterminado. Sin embargo , puede hacerlo en la definición de la función y solo aquellos que vean la definición podrán usar el valor predeterminado.
Si las funciones están expuestas (no miembros, públicas o protegidas), la persona que llama debe conocerlas y los valores predeterminados deben estar en el encabezado.
Si las funciones son privadas y están fuera de línea, entonces tiene sentido colocar los valores predeterminados en el archivo de implementación porque eso permite cambios que no activan la recompilación del cliente (un problema a veces grave para las bibliotecas de bajo nivel compartidas en escala empresarial). desarrollo). Dicho esto, definitivamente es potencialmente confuso, y hay un valor de documentación al presentar la API de una manera más intuitiva en el encabezado, así que elija su compromiso, aunque la consistencia es lo principal cuando no hay ninguna razón convincente.
Un punto más que no he encontrado a nadie mencionado:
¡Si tiene un método virtual, cada declaración puede tener su propio valor predeterminado!
Depende de la interfaz a la que llame, el valor que se utilizará.
Ejemplo en ideone
struct iface
{
virtual void test(int a = 0) { std::cout << a; }
};
struct impl : public iface
{
virtual void test(int a = 5) override { std::cout << a; }
};
int main()
{
impl d;
d.test();
iface* a = &d;
a->test();
}
Imprime 50
Te desanimo fuertemente a usarlo así