videos - Uso excesivo de `this` en C++
uniones en c ejemplos (15)
El nombre de campo no tiene nada que ver con un codesmell. Como dijo Neil , la visibilidad en el campo es el único código que existe aquí.
Hay varios artículos sobre convenciones de nombres en C ++:
- ¿Convención de nomenclatura para variable pública y privada?
- Método privado de convención de nombres
- c ++ uso de espacio de nombres y reglas de nombres
etc.
Esta pregunta ya tiene una respuesta aquí:
- ¿Cuándo debo hacer un uso explícito del puntero `this`? 13 respuestas
Estoy tratando con una base de código grande que usa la siguiente construcción a lo largo de
class MyClass
{
public:
void f(int x);
private:
int x;
};
void MyClass::f(int x)
{
''
''
this->x = x;
''
''
}
Personalmente, siempre he usado y por eso prefiero la forma.
class MyClass
{
public:
void f(int x);
private:
int _x;
};
void MyClass::f(int x)
{
''
''
_x = x;
''
''
}
Las razones por las que prefiero esto último es que es más sucinto (menos código = menos errores potenciales) y que no me gusta tener múltiples variables del mismo nombre en el alcance al mismo tiempo donde puedo evitarlo. Dicho esto, estoy viendo el uso anterior cada vez más a menudo en estos días. ¿Hay alguna ventaja al segundo enfoque que desconozco? (por ejemplo, el efecto en el tiempo de compilación, el uso con código de plantilla, etc.) ¿Son las ventajas de cualquiera de los enfoques lo suficientemente importantes como un refactor para el otro? Razón por la que pregunto, que si bien no me gusta el segundo enfoque presente en el código, la cantidad de esfuerzo y el riesgo asociado de introducir más errores no merecen un refactor.
En mi opinión, esto tiende a añadir desorden al código, por lo que tiendo a usar diferentes nombres de variables (según la convención, podría ser un guión bajo, m_ , lo que sea).
Este uso de ''esto'' está recomendado por los estándares de codificación de Microsoft C #. Proporciona una buena claridad de código, y pretende ser un estándar sobre el uso de m_ o _ o cualquier otra cosa en las variables miembro.
Honestamente, realmente no me gusta subrayar los nombres, prefijo a todos mis miembros con una ''m''.
Estoy de acuerdo. No me gusta esa convención de nombres, prefiero una donde hay una distinción obvia entre las variables miembro y las variables locales. ¿Qué pasa si dejas this
?
Hoy en día, la mayoría de los editores de IDE colorean sus variables para indicar miembros de clase de variables locales. Por lo tanto, IMO, ni prefijos ni ''this->'' deberían ser necesarios para la legibilidad.
Mi opinión personal es que luchar contra una convención de codificación existente es algo que no debes hacer. Como Sutter / Alexandrescu lo pone en su libro ''Convenciones de codificación en C ++'': no se preocupe por las cosas pequeñas. Cualquiera puede leer lo uno o lo otro, ya sea que haya un ''this->'' o ''_'' al principio o lo que sea.
Sin embargo, la coherencia en las convenciones de nomenclatura es algo que normalmente desea, por lo que adherirse a una convención en algún ámbito (al menos el alcance del archivo, idealmente toda la base de código, por supuesto) se considera una buena práctica. Usted mencionó que este estilo se usa en una base de código más grande, por lo que creo que la modificación de otra convención sería una mala idea.
Si, después de todo, encuentra que hay una buena razón para cambiarlo, no lo haga manualmente. En el mejor de los casos, su IDE admite este tipo de ''refactorizaciones''. De lo contrario, escribe un script para cambiarlo. Buscar y reemplazar debe ser la última opción. En cualquier caso, debe tener una copia de seguridad (control de origen) y algún tipo de instalación de prueba automatizada. De lo contrario no te divertirás con eso.
Mucha gente usa esto porque en su IDE aparecerá una lista de identificadores de la clase actual.
Sé que lo hago en BCB.
Creo que el ejemplo que proporciona con el conflicto de nombres es una excepción. Sin embargo, en Delphi, las pautas de estilo usan un prefijo (generalmente "a") para los parámetros para evitar exactamente esto.
No me gusta usar "esto" porque es atávico. Si estás programando en C antiguo (¿recuerdas C?), Y quieres imitar algunas de las características de la POO, creas una estructura con varios miembros (estas son análogas a las propiedades de tu objeto) y creas un conjunto de funciones que tienen un puntero a esa estructura como su primer argumento (son análogos a los métodos de ese objeto).
(Creo que esta sintaxis de typedef es correcta pero ha sido un tiempo ...)
typedef struct _myclass
{
int _x;
} MyClass;
void f(MyClass this, int x)
{
this->_x = x;
}
De hecho, creo que los compiladores más antiguos de C ++ compilarían su código en la forma anterior y luego lo pasarían al compilador de C. En otras palabras, hasta cierto punto, C ++ era solo azúcar sintáctica. Así que no estoy seguro de por qué alguien querría programar en C ++ y volver a usar explícitamente "esto" en el código. Tal vez sea "Nutrisweet sintáctico".
Si tiene un problema con las convenciones de nombres, puede intentar usar algo como lo siguiente.
class tea
{
public:
int cup;
int spoon;
tea(int cups, int spoons);
};
o
class tea
{
public:
int cup;
int spoon;
tea(int drink, int sugar);
};
Creo que tienes la idea. Es básicamente nombrar las variables diferentes pero "iguales" en el sentido lógico. Espero que ayude.
Su versión es un poco más limpia, pero mientras lo hace, yo:
- Evite el guión bajo: _x está bien hasta que alguien elija _MyField, que es un nombre reservado. Un subrayado inicial seguido de una letra mayúscula no está permitido como nombre de variable. Vea: ¿Cuáles son las reglas sobre el uso de un guión bajo en un identificador de C ++?
- Haga que el atributo sea privado o protegido: el cambio es seguro si se compila, y se asegurará de que se usará su configurador.
- La historia this-> tiene un uso, por ejemplo, en código con plantilla para hacer que el nombre del campo dependa de su tipo (puede resolver algunos problemas de búsqueda).
Un pequeño ejemplo de resoluciones de nombres que se arreglan utilizando un explícito this-> (probado con g ++ 3.4.3):
#include <iostream>
#include <ostream>
class A
{
public:
int g_;
A() : g_(1) {}
const char* f() { return __FUNCTION__; }
};
const char* f() { return __FUNCTION__; }
int g_ = -1;
template < typename Base >
struct Derived : public Base
{
void print_conflicts()
{
std::cout << f() << std::endl; // Calls ::f()
std::cout << this->f() << std::endl; // Calls A::f()
std::cout << g_ << std::endl; // Prints global g_
std::cout << this->g_ << std::endl; // Prints A::g_
}
};
int main(int argc, char* argv[])
{
Derived< A >().print_conflicts();
return EXIT_SUCCESS;
}
Usar ''esto'' de esta manera es IMO, no un olor de código, sino simplemente una preferencia personal. Por lo tanto, no es tan importante como la coherencia con el resto del código en el sistema. Si este código es inconsistente, podría cambiarlo para que coincida con el otro código. Si al cambiarlo introducirás una inconsistencia con la mayoría del resto del código, eso es muy malo y lo dejaría solo.
No querrás volver a jugar al tenis de código en el que alguien cambia algo simplemente para que se vea "bien" solo para que alguien más venga con diferentes gustos que luego lo cambien de nuevo.
Yo siempre uso la convención de nombrar m_ Aunque no me gusta la "notación húngara" en general, me parece muy útil ver muy claramente si estoy trabajando con datos de miembros de clase. Además, encontré que usar 2 nombres de variables idénticos en el mismo ámbito también es propenso a errores.
Es más normal en C ++ que los miembros se inicialicen en la construcción utilizando el inicializador.
Para hacerlo, debe usar un nombre diferente al nombre de la variable miembro.
Así que aunque usaría Foo(int x) { this.x = x; }
Foo(int x) { this.x = x; }
en Java, no lo haría en C ++.
El verdadero olor podría ser la falta de uso de inicializadores y métodos que no hacen nada más que mutar las variables miembro, en lugar del uso de this -> x
sí.
¿Alguien sabe por qué es una práctica universal en todas las tiendas de C ++ en las que he usado nombres diferentes para los argumentos de constructor de las variables miembro cuando se utilizan con inicializadores? ¿Hubo algunos compiladores de C ++ que no lo soportaron?
class MyClass
{
public:
int m_x;
void f(int p_x);
};
void MyClass::f(int p_x)
{
m_x = p_x;
}
... es mi forma preferida usando prefijos de alcance. m_ para miembro, p_ para parámetro (algunos usan a_ para argumento en su lugar), g_ para global y algunas veces l_ para local si ayuda a la legibilidad.
Si tiene dos variables que merecen el mismo nombre, esto puede ayudar mucho y evita tener que inventar algunas variaciones aleatorias en su significado solo para evitar la redefinición. O incluso peor, el temido ''x2, x3, x4, etc'' ...
class MyClass{
public:
int x;
void f(int xval);
};
//
void MyClass::f(int xval){
x = xval;
}