Cita:
Iniciado por dmorill Me he quedado de piedra, no debería compilar pues según entiendo el "="no está definido para esas estructuras.
Código C++:
Ver originalstruct Punto{
int x;
int y;
Punto(int x=0, int y=0)
: x(x), // estoy copiando un int en otro int
y(y) // estoy copiando un int en otro int
{ }
// Equivalencia más conocida:
Punto(int x=0, int y=0)
{
this->x = x;
this->y = y;
}
};
Pregunta: ¿Por qué no hace falta usar (y de hecho no puedes)
this en el primer constructor?
Porque la sección que sigue a los dos puntos es única y exclusivamente para inicializar la clase, luego no permite modificar elementos que no pertenezcan a la misma. Entonces, el primer
x que sigue a los dos puntos únicamente puede ser la variable miembro... en el caso de la
x que está entre los paréntesis, ésta podría ser bien la variable miembro o bien el parámetro de la función. Como en caso de colisión de nombres el compilador va a usar el que tenga un ámbito menor en este caso va a elegir SIEMPRE la variable pasada como parámetro (el ámbito de la variable miembro es mayor porque al salir del constructor la variable miembro sigue existiendo).
Pregunta: ¿Qué aporta usar esta forma a la hora de diseñar los constructores?
Las ventajas son varias:
- Es la única forma de llamar a los constructores de las clase padre en el caso de herencia.
- A partir del estándar C++11 se pueden llamar a constructores de la misma clase desde cualquier otro constructor... estas llamadas únicamente se pueden hacer con el diseño que te he propuesto.
- Crear constructores de la segunda forma puede provocar una pérdida de rendimiento. Si alguna variable miembro es una clase y no se inicializa en la zona de inicialización el constructor llamará a su constructor por defecto... si después se modifica el valor de dicha variable usando el operador = se realizará una copia... dos llamadas que normalmente se superponen en vez de una:
Código C++:
Ver originalstruct A
{
A()
{ std::cout << "A::A()" << std::endl; }
A(int)
{ std::cout << "A::A(int)" << std::endl; }
A(const A&)
{ std::cout << "A::A(const A&)" << std::endl; }
A& operator=(const A&)
{
std::cout << "A& operator=(const A&)" << std::endl;
return *this;
}
};
struct B
{
A a;
B(A& copia)
{
a = copia;
}
// El bool de este constructor lo he puesto únicamente para diferenciar ambos constructores
B(A& copia, bool)
: a(copia)
{ }
};
int main()
{
A dummy;
std::cout << std::endl
<< "Dos llamadas: constructor por defecto y operador de asignación."
<< std::endl;
B b1(dummy);
std::cout << std::endl
<< "Una única llamada: constructor copia"
<< std::endl;
B b2(dummy,false);
}
Cita:
Iniciado por dmorill Tuve que compilarlo yo mismo y si de hecho funciona, que peligro usarlo así de ese modo, por qué permite c++ eso?
Con lo expuesto anteriormente queda claro que no es peligroso. Piensa que C++ implementa por defecto el operador de asignación y realiza una copia simple y llana del estado del objeto... esta opción está bien mientras no tires de memoria dinámica, en cuyo caso tienes que reimplementar dicho operador o directamente evitar su implementación. Para esto último puedes marcar la función como borrada y así evitas que el compilador cree la versión por defecto (nuevamente C++11):
Código C++:
Ver originalstruct Test1
{
Test1& operator=(const Test1&) = delete;
};
struct Test2
{
};
int main()
{
Test1 t11, t12;
t11 = t12; // Error, operador de asignación no disponible
Test2 t21,t22;
t21 = t22; // OK
}
Esto es aplicable también a constructores, funciones heredadas, ...
Cita:
Iniciado por dmorill Cambie el struct por un class y ya no compila, es decir que solo es para estructuras.
Lógico. La única diferencia en C++ entre un
struct y una
class es la visibilidad por defecto. En un
struct los elementos son, salvo que se indique lo contrario, públicos, mientras que en una
class son privados... por eso en una class es habitual encontrar
public:... es la única forma de generar la interfaz pública de la clase.
Cita:
Iniciado por dmorill El código es super largo pero pondré lo respecto a la pregunta, si quieres el resto solo de dices y con gusto lo pongo todo. Te describo lo que estaba haciendo...
Lo siento, sigo sin entender para qué necesitas la función
nextVecino. Tal vez si pones el código completo para intentar entender el uso que pretendes darle...
Un saludo.