2012-10-10 47 views
5

Duplicar posibles:
Members vs method arguments access in C++Los conflictos entre los nombres de los miembros y los nombres de los argumentos de constructor

tengo una clase que tiene algunos miembros, como x, y, width y height. En su constructor, yo no haría esto:

A::A(int x, int y, int width, int height) 
{ 
    x = x; 
    y = y; 
    width = width; 
    height = height; 
} 

Esto no tiene mucho sentido y cuando se compila con g ++ x, y, width, y height convertido en valores extraños (por ejemplo -1405737648).

¿Cuál es la forma óptima de resolver estos conflictos de nomenclatura?

+3

Euh, agregando un 'a' a los nombres de los argumentos? –

+0

'A :: A (int xa, int, int widtha, int heighta)' – corazza

+0

si quiere ser elegante, * pre * pend the 'a', formando un artículo indefinido en inglés:' anX, aY, aWidth, aHaight' etc. Obviamente, el mismo identificador no puede utilizarse para referirse a dos variables diferentes en el mismo ámbito. Ver mi respuesta –

Respuesta

17

puede usar listas de inicialización muy bien con los mismos nombres:

A::A(int x, int y, int width, int height) : 
    x(x), 
    y(y), 
    width(width), 
    height(height) 
{ 
} 

Una alternativa es utilizar diferentes nombres, si no quieren tener los mismos nombres. Alguna variación-notación húngara viene a la mente (que podría conseguir un poco de odio para esto):

//data members 
int x_; 
int y_; 
int width_; 
int height_; 
//constructor 
A::A(int x, int y, int width, int height) : 
    x_(x), 
    y_(y), 
    width_(width), 
    height_(height) 
{ 
} 

pero no hay nada de malo en la primera sugerencia.

+0

17.4.3.1.2/1: cada nombre que comienza con un guión bajo se reserva a la implementación para utilizarlo como nombre en el espacio de nombres global. –

+0

@JohnDibling ¿por qué creo que solo se aplica a las macros? Oh, bueno ... supongo que hay una cosa más que odiaré cuando miro hacia atrás en el código anterior que he escrito ...: D –

+0

¿Qué pasa con la notación húngara? ;) Aunque, esto es en realidad solo un nombre prefijado, no realmente una variante de la notación húngara. –

2

Aunque puede evitar el problema utilizando la lista de inicialización del constructor, sugiero seguir una convención para nombrar miembros de datos, por ejemplo, un _ posterior, o un m_ líder. De lo contrario, es muy probable que tenga conflictos de nombres, especialmente si tiene miembros con nombres como x y y.

class A 
{ 
    public: 

    A(int x, int y, int width, int height) : x_(x), y_(y), with_(width), height_(height) {} 

    int x_; 
    int y_; 
    int width_; 
    int height_; 
}; 
+0

A menudo vi esta convención (subrayado final): ¿conoces su origen? Gracias por cualquier pista. – Wolf

+0

this-> es también una excelente manera de eliminar ambigüedades del ámbito local. – partyd

5

Si tiene que usar asignaciones en el constructor (en lugar de utilizar una lista de valores de inicialización, que se prefiere) el patrón específico para abordar este problema es utilizar this puntero, de la siguiente manera:

this->a = a; 
0

Puede simplemente cambiar los nombres de los argumentos del constructor. Cuando se escribe

A::A(int x, int y, int width, int height) 
{ 
    x = x; 
    y = y; 
    width = width; 
    height = height; 
} 

entonces usted está asignando los argumentos del constructor para sí mismos, dejando a las variables de instancia reales sin inicializar, es por eso que está obteniendo los valores falsos.

La solución general sugiero (y ampliamente utilizado) para cambiar los nombres de los argumentos del método constructor:

A::A(int x_initial, int y_initial, int width_initial, int height_initial) 
{ 
    x = x_initial; 
    y = y_initial; 
    width = width_initial; 
    height = height_initial; 
} 
+0

Sí, eso es lo que hice, pero en lugar de "_inicial" agregué "a". – corazza

+0

@Bane y qué pasa con eso? –

+0

Bueno, parece ser una solución "fea", y supuse que sugería que había algo mal en mi comprensión de los constructores ... – corazza

2

Si es posible, es mejor fijar los miembros de datos a través de la lista de inicialización, en cuyo caso no hay problema con los argumentos que sombrean los nombres de los miembros. Otra alternativa es usar this->foo = foo; en el cuerpo del constructor. Existe un problema similar para los instaladores, pero ahora no puede usar la solución de la lista de inicializadores. Estás atrapado con this->foo = foo; - o simplemente usa diferentes nombres para argumentos y miembros.

Algunas personas realmente odian los argumentos que ocultan a los miembros de datos; múltiples estándares de codificación explícitamente dicen nunca hacer esto. Otros piensan que este tipo de sombreado, al menos para los constructores y setters, es el maullido del gato. Recuerdo leer uno o dos estándares de codificación (pero no recuerdo cuál) que designaron a este tipo de ocultamiento como una práctica de "debería" (pero no "deberá").

Una última opción es usar el sombreado en la declaración de función para dar a los lectores una pista sobre lo que hace la función, pero use nombres distintos en la implementación.

Actualización: ¿Qué es "shadowing"?

#include <iostream> 

void printi (int i) { std::cout << "i=" << i << "\n"; } 

int i = 21; 

int main() { 
    printi (i); 
    int i = 42; 
    printi (i); 
    for (int i = 0; i < 3; ++i) { 
     printi (i); 
     int i = 10; 
     printi (i); 
    } 
    printi (i); 
} 

La declaración más interna de i, int i=10, sombras i la variable declarada en la declaración for, que a su vez las sombras de la variable i declarado en ámbito de la función, que a su vez las sombras de la variable global i.

En el problema en cuestión, los argumentos x, y, width, y height al constructor no predeterminado para la clase A sombra los datos de los miembros con los mismos nombres que los argumentos.

Su width=width; no hizo nada porque el argumento width sombrea (oculta) el miembro de datos width. Cuando tiene dos o más variables con el mismo nombre que se declararon en diferentes ámbitos, el ganador siempre es el nombre con el alcance más interno. En general, siempre gana el nombre con el alcance más interno.

+0

¿A qué se refiere exactamente como "sombreado"? – corazza

+0

@Bane - ¿Qué es "sombra?" Sombreado: (1) Un dispositivo de tortura utilizado para evaluar si los estudiantes de CS 101 comprenden el alcance. (2) Cuando una variable declarada en algún ámbito tiene el mismo nombre que una variable declarada en algún ámbito externo. (3) Lo que hiciste con tu constructor. (4) Un problema potencial que se detecta compilando '-Wshadow'. (5) Vea mi respuesta actualizada. –

+0

¡Ahora lo entiendo, gracias! – corazza

Cuestiones relacionadas