Ver Mensaje Individual
  #9 (permalink)  
Antiguo 11/02/2016, 09:33
eferion
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Incrementar un iterador de un vector<MyClass>

Cita:
Iniciado por dmorill Ver Mensaje
Me he quedado de piedra, no debería compilar pues según entiendo el "="no está definido para esas estructuras.
Código C++:
Ver original
  1. struct Punto{
  2.   int x;
  3.   int y;
  4.  
  5.   Punto(int x=0, int y=0)
  6.     : x(x), // estoy copiando un int en otro int
  7.       y(y) // estoy copiando un int en otro int
  8.   { }
  9.  
  10.   // Equivalencia más conocida:
  11.   Punto(int x=0, int y=0)
  12.   {
  13.     this->x = x;
  14.     this->y = y;
  15.   }
  16. };

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 original
    1. struct A
    2. {
    3.   A()
    4.   { std::cout << "A::A()" << std::endl; }
    5.  
    6.   A(int)
    7.   { std::cout << "A::A(int)" << std::endl; }
    8.  
    9.   A(const A&)
    10.   { std::cout << "A::A(const A&)" << std::endl; }
    11.  
    12.   A& operator=(const A&)
    13.   {
    14.     std::cout << "A& operator=(const A&)" << std::endl;
    15.     return *this;
    16.   }
    17. };
    18.  
    19. struct B
    20. {
    21.   A a;
    22.  
    23.   B(A& copia)
    24.   {
    25.     a = copia;
    26.   }
    27.  
    28.   // El bool de este constructor lo he puesto únicamente para diferenciar ambos constructores
    29.   B(A& copia, bool)
    30.     : a(copia)
    31.   { }
    32. };
    33.  
    34. int main()
    35. {
    36.   A dummy;
    37.  
    38.   std::cout << std::endl
    39.             << "Dos llamadas: constructor por defecto y operador de asignación."
    40.             << std::endl;
    41.   B b1(dummy);
    42.  
    43.   std::cout << std::endl
    44.             << "Una única llamada: constructor copia"
    45.             << std::endl;
    46.   B b2(dummy,false);
    47. }

Cita:
Iniciado por dmorill Ver Mensaje
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 original
  1. struct Test1
  2. {
  3.   Test1& operator=(const Test1&) = delete;
  4. };
  5.  
  6. struct Test2
  7. {
  8. };
  9.  
  10. int main()
  11. {
  12.   Test1 t11, t12;
  13.  
  14.   t11 = t12; // Error, operador de asignación no disponible
  15.  
  16.   Test2 t21,t22;
  17.   t21 = t22; // OK
  18. }

Esto es aplicable también a constructores, funciones heredadas, ...


Cita:
Iniciado por dmorill Ver Mensaje
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 Ver Mensaje
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.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.