que - programas en c++ ejemplos avanzados pdf
ParĂ¡metros por defecto con constructores C++ (12)
Cualquiera de los enfoques funciona. Pero si tiene una larga lista de parámetros opcionales, cree un constructor por defecto y luego haga que su función set devuelva una referencia a esto. Luego encadena los reguladores.
class Thingy2
{
public:
enum Color{red,gree,blue};
Thingy2();
Thingy2 & color(Color);
Color color()const;
Thingy2 & length(double);
double length()const;
Thingy2 & width(double);
double width()const;
Thingy2 & height(double);
double height()const;
Thingy2 & rotationX(double);
double rotationX()const;
Thingy2 & rotatationY(double);
double rotatationY()const;
Thingy2 & rotationZ(double);
double rotationZ()const;
}
main()
{
// gets default rotations
Thingy2 * foo=new Thingy2().color(ret)
.length(1).width(4).height(9)
// gets default color and sizes
Thingy2 * bar=new Thingy2()
.rotationX(0.0).rotationY(PI),rotationZ(0.5*PI);
// everything specified.
Thingy2 * thing=new Thingy2().color(ret)
.length(1).width(4).height(9)
.rotationX(0.0).rotationY(PI),rotationZ(0.5*PI);
}
Ahora, cuando construyas los objetos, puedes escoger y elegir qué propiedades anular y cuáles has establecido se nombran explícitamente. Mucho más legible :)
Además, ya no tiene que recordar el orden de los argumentos al constructor.
¿Es una buena práctica tener un constructor de clase que use parámetros predeterminados, o debería usar constructores sobrecargados separados? Por ejemplo:
// Use this...
class foo
{
private:
std::string name_;
unsigned int age_;
public:
foo(const std::string& name = "", const unsigned int age = 0) :
name_(name),
age_(age)
{
...
}
};
// Or this?
class foo
{
private:
std::string name_;
unsigned int age_;
public:
foo() :
name_(""),
age_(0)
{
}
foo(const std::string& name, const unsigned int age) :
name_(name),
age_(age)
{
...
}
};
Cualquiera de las versiones parece funcionar, por ejemplo:
foo f1;
foo f2("Name", 30);
¿Qué estilo prefieres o recomiendas y por qué?
Cuestión de estilo, pero como dijo Matt, definitivamente considere marcar a los constructores con argumentos predeterminados que permitan la conversión implícita como ''explícita'' para evitar la conversión automática involuntaria. No es un requisito (y puede que no sea preferible si está realizando una clase contenedora a la que desea convertir implícitamente), pero puede evitar errores.
Personalmente me gustan los valores predeterminados cuando corresponde, porque no me gusta el código repetido. YMMV.
Definitivamente una cuestión de estilo. Prefiero constructores con parámetros predeterminados, siempre que los parámetros tengan sentido. Las clases en el estándar también las usan, lo que habla a su favor.
Una cosa a tener en cuenta es que si tiene valores predeterminados para todos los parámetros excepto uno, su clase se puede convertir implícitamente a partir de ese tipo de parámetro. Mira este hilo para más información.
Elección principalmente personal. Sin embargo, la sobrecarga puede hacer cualquier cosa que el parámetro predeterminado pueda hacer, pero no viceversa.
Ejemplo:
Puede usar sobrecarga para escribir A (int x, foo y a) y A (int x), pero no puede usar el parámetro predeterminado para escribir A (int x, foo & = null).
La regla general es usar lo que sea que tenga sentido y hace que el código sea más legible.
En mi experiencia, los parámetros predeterminados parecen ser geniales en ese momento y hacen que mi factor de pereza sea feliz, pero en el futuro utilizo la clase y me sorprende cuando aparece el valor predeterminado. Así que realmente no creo que sea una buena idea ; mejor tener un className :: className () y luego un className :: init ( arglist ). Solo por ese margen de mantenibilidad.
Esta discusión se aplica tanto a los constructores, como a los métodos y funciones.
¿Usando parámetros predeterminados?
Lo bueno es que no tendrá que sobrecargar constructores / métodos / funciones para cada caso:
// Header
void doSomething(int i = 25) ;
// Source
void doSomething(int i)
{
// Do something with i
}
Lo malo es que debes declarar tu valor predeterminado en el encabezado, por lo que tienes una dependencia oculta: como cuando cambias el código de una función en línea, si cambias el valor predeterminado en tu encabezado, necesitarás recompilar todas las fuentes usando este encabezado para asegurarse de que usarán el nuevo valor predeterminado.
Si no lo hace, las fuentes seguirán usando el antiguo valor predeterminado.
¿usando constructores / métodos / funciones sobrecargados?
Lo bueno es que si sus funciones no están en línea, entonces usted controla el valor predeterminado en la fuente eligiendo cómo se comportará una función. Por ejemplo:
// Header
void doSomething() ;
void doSomething(int i) ;
// Source
void doSomething()
{
doSomething(25) ;
}
void doSomething(int i)
{
// Do something with i
}
El problema es que debe mantener múltiples constructores / métodos / funciones y sus reenvíos.
Me gustaría ir con los argumentos predeterminados, especialmente dado que C ++ no te permite encadenar constructores (por lo que terminas teniendo que duplicar la lista de inicializadores, y posiblemente más, para cada sobrecarga).
Dicho esto, hay algunas trampas con argumentos predeterminados, incluido el hecho de que las constantes pueden estar en línea (y por lo tanto convertirse en parte de la interfaz binaria de su clase). Otro aspecto a tener en cuenta es que agregar argumentos predeterminados puede convertir un constructor explícito de argumentos múltiples en un constructor implícito de un argumento:
class Vehicle {
public:
Vehicle(int wheels, std::string name = "Mini");
};
Vehicle x = 5; // this compiles just fine... did you really want it to?
Me gustaría ir con los parámetros predeterminados, por esta razón: su ejemplo asume que los parámetros de ctor corresponden directamente a las variables de los miembros. Pero, ¿qué pasa si ese no es el caso? Y debe procesar los parámetros antes de que el objeto se inicialice. Tener una ctor común sería la mejor manera de hacerlo.
Si crear constructores con argumentos es malo (como muchos argumentarían), hacerlos con argumentos predeterminados es aún peor. Recientemente comencé a darme la opinión de que los argumentos de los ctores son malos, porque la lógica de tu ctor debe ser lo más mínima posible . ¿Cómo se maneja el manejo de errores en el ctor, si alguien pasa una discusión que no tiene sentido? Puede lanzar una excepción, lo cual es una mala noticia a menos que todas las personas que llaman estén preparadas para envolver las llamadas "nuevas" dentro de los bloques try, o establecer alguna variable miembro "is-initialized", que es una especie de hack sucio.
Por lo tanto, la única forma de asegurarse de que los argumentos pasen a la etapa de inicialización de su objeto es configurar un método de inicialización () separado donde pueda verificar el código de retorno.
El uso de argumentos predeterminados es malo por dos razones; Antes que nada, si quieres agregar otro argumento al ctor, entonces estás atascado poniéndolo al principio y cambiando toda la API. Además, la mayoría de los programadores están acostumbrados a descifrar una API por la forma en que se usa en la práctica; esto es especialmente cierto para las API no públicas que se usan dentro de una organización donde la documentación formal puede no existir. Cuando otros programadores ven que la mayoría de las llamadas no contienen ningún argumento, harán lo mismo, permaneciendo felizmente inconscientes del comportamiento predeterminado que sus argumentos predeterminados les imponen.
Además, vale la pena señalar que la guía de estilo de google C ++ evita tanto los argumentos de Ctor (a menos que sea absolutamente necesario) como los argumentos predeterminados para funciones o métodos .
Una cosa más a considerar es si la clase podría usarse o no en una matriz:
foo bar[400];
En este escenario, no hay ninguna ventaja al usar el parámetro predeterminado.
Esto ciertamente NO funcionaría:
foo bar("david", 34)[400]; // NOPE
Una cosa que me molesta con los parámetros predeterminados es que no puede especificar los últimos parámetros, sino que usa los valores predeterminados para los primeros. Por ejemplo, en su código, no puede crear un Foo sin nombre pero con una edad determinada (sin embargo, si mal no recuerdo, esto será posible en C ++ 0x, con la sintaxis de construcción unificada). A veces, esto tiene sentido, pero también puede ser muy incómodo.
En mi opinión, no hay una regla general. Personalmente, tiendo a usar múltiples constructores (o métodos) sobrecargados, excepto si solo el último argumento necesita un valor predeterminado.
Sam''s respuesta Sam''s da la razón de que los argumentos predeterminados son preferibles para los constructores en lugar de la sobrecarga. Solo quiero agregar que C ++ - 0x permitirá la delegation de un constructor a otro, eliminando así la necesidad de los valores predeterminados.