Help with c ++ program? [closed]

1

It's a problem with the pointers. Here I have a program that gives "high" soccer players, asks the name of the coach, and then asks you to fill some fields about the information of your players.

The problem is that the program stops working when you select that you want to register 3 players, that is, it lets you fill out all the fields, but at the time of printing the data, the program crashes.

I checked it by removing pointers, and it worked. And I honestly can not understand the problem.

This is my code:

using namespace std;

#include<iostream>
#include<cstdlib>
#include <stdio.h>

class Persona
 {
      private:
            string NomComp;
            int Edad;


     public:
        Persona( string NC = " " , int E = 1 );

        void Leer( void );
        void Imprimir( void );

 };



Persona::Persona( string NC , int E ) : NomComp ( NC ) , Edad ( E )
 {

 }

void Persona::Leer( void )
 {

    cout<< "\t\tDame el Nombre Completo: " ;
    getline( cin, NomComp);
    cout<< "\t\tDame la Edad: ";
    cin>> Edad;

    cout<< endl;
    fflush ( stdin );

 }

void Persona::Imprimir( void )
 {
    cout<< "\t\tNombre Completo :" << NomComp << endl;

    cout<< "\t\tEdad : " << Edad << endl;       
 }


class Jugador : public Persona
 {
    private:
        string Posicion;
        string Apodo;
        string Equipo;


    public:
        Jugador ( string NC = " " , int E = 1 , string P = " " , 
                  string A = " " , string Eq = " " );

        void Leer( void );
        void Imprimir( void ) ;

 };



Jugador::Jugador ( string NC  , int E  , string P , string A  , string Eq  ) 
                  : Persona ( NC , E), Posicion ( P ) , Apodo ( A ) , 
                   Equipo ( Eq )
 {

 }      



void Jugador::Leer( void )
 {
    static int n = 1;

    cout << "\t\tJugador : " << n << endl;
    Persona::Leer();
    cout << "\t\tPosicion : ";
    getline(cin, Posicion);
    cout << "\t\tApodo : ";
    getline(cin, Apodo);
    cout << "\t\tEquipo : ";
    getline(cin, Equipo);

    cout << endl;

    n++;

 }
void Jugador::Imprimir( void ) 

 {
    static int n = 1;

    cout << "Jugador " << n << endl;
    Persona::Imprimir( );
    cout << "\t\tPosicion : " << Posicion << endl
         << "\t\tApodo    : " << Apodo << endl
         << "\t\tEquipo   : " << Equipo
         << endl << endl;

    n++;

 }


class Seleccion : public Jugador

 {
    private:
        string Pais;


        Persona* ApDT;

        int NumJug;
        Jugador* ArreJug;

    public:
        Seleccion ( int NJ = 2 , string Pa = " ");
        Seleccion( Seleccion& Sel);


        void Leer( void );
        void Imprimir( void );

        Seleccion& operator = ( Seleccion& Sel2 );

        ~Seleccion( void );

 };

Seleccion::Seleccion ( int NJ, string Pa ) : NumJug ( NJ ), Pais ( Pa ) 

 {
      ApDT = new Persona;

      ArreJug = new Jugador[ NumJug ];
 }


Seleccion::Seleccion( Seleccion& Sel)
    {
        Pais = Sel.Pais;

        ApDT = new Persona;
        *ApDT = *( Sel.ApDT );

        NumJug = Sel.NumJug;
        ArreJug = new Jugador[ NumJug ];

        for ( int i = 0; i < NumJug; i++)
            ArreJug [ i ] = Sel.ArreJug [ i ];  
    }

void Seleccion:: Leer( void )
    {

    fflush ( stdin );
    cout << "Dame El Pais: ";
    getline (cin,Pais);
    cout << "Nombre del Director Tecnico" << endl;
    ApDT-> Leer ();
    for (int i = 0;i < NumJug; i++)
      {
        ArreJug[i].Leer (); 
      }
    cout << endl;

    }

void Seleccion:: Imprimir( void )

    {

    cout << "Pais: " << Pais << endl;
    cout << "Nombre del Director Tecnico: "
         << endl;
    ApDT->Imprimir();

    cout << "Jugadores " << endl;

        for (int i = 0 ; i < NumJug ; i++)
        {
          ArreJug[i].Imprimir();    
        }

    }

Seleccion& Seleccion::operator = ( Seleccion& Sel2 )
    {
        if ( this != &Sel2 )
            {
                if ( NumJug != Sel2.NumJug )
                    {
                            delete[] ArreJug;
                            ArreJug = new Seleccion [Sel2.NumJug];
                    }

                Pais = Sel2.Pais;
                *ApDT = *( Sel2.ApDT);
                NumJug = Sel2.NumJug;

                for ( int i = 0; i < NumJug; i++)
                    ArreJug [ i ] = Sel2.ArreJug [ i ];
            }
        return *this;

    }

Seleccion::~Seleccion( void )
 {
    delete ApDT;
    delete[] ArreJug;   

 }


int NumeroJug ( void );

int NumeroJug ( void )

 {
    int NJ;
    cout << "Dame el numero de Jugadores: ";
    cin >> NJ;
    cout << endl;

    return NJ;  
 }

int main ( void )
 {

    system( "cls");

    int NJ;
    NJ = NumeroJug();

    Seleccion* AptP;
    AptP = new Seleccion ( NJ );

    AptP->Leer( );


    Seleccion* AptP2 = new Seleccion;
    Seleccion* AptP3 = new Seleccion;

    *AptP3 = *AptP2 = *AptP;

    cout << "ORIGINAL" << endl;
    AptP -> Imprimir( );
    cout << "ASIGNADO" << endl;
    AptP2 -> Imprimir ( );
    cout << "ASIGNADO" << endl;
    AptP3 -> Imprimir ( );

    delete AptP2;
    delete AptP3;
    delete AptP;

    system( "pause ");


    return 0;
 }
    
asked by Alex Villegas 16.05.2017 в 03:38
source

1 answer

1
Seleccion::Seleccion( Seleccion& Sel)
{
  for ( int i = 0; i < NumJug; i++)
    ArreJug [ i ] = Sel.ArreJug [ i ]; // <<---
}

Seleccion& Seleccion::operator = ( Seleccion& Sel2 )
{
  for ( int i = 0; i < NumJug; i++)
    ArreJug [ i ] = Sel2.ArreJug [ i ]; // <<---
}

The lines highlighted with the comment make a copy of objects ... Are you sure that with polymorphism you want to do that?

struct A
{
  virtual void test()
  { std::cout << "A"; }
}

struct B : A
{
  void test()
  { std::cout << "B"; }
}

int main()
{
  B *b = new B();

  b->test(); // Imprime B

  A a = *b;
  a.test(); // Imprime A

  delete b;
}

When you make a copy of an object you lose all the polymorphism you may have created. To solve this problem in cases of polymorphism it is usual to resort to the list of pointers (in your case ArreJug should be a double pointer) and cloning:

struct A
{
  virtual void test()
  { std::cout << "A"; }

  virtual A* clone()
  { return new A(this); }
}

struct B : A
{
  void test()
  { std::cout << "B"; }

  void clone()
  { return new B(this); }
}

int main()
{
  B *b = new B();

  b->test(); // Imprime B

  A* a = b->clone();
  a->test(); // Imprime B

  delete b;
  delete a;
}

What happens is that you do not get to find this error because before it is producing a complicated one to find:

Seleccion& Seleccion::operator = ( Seleccion& Sel2 )
{
  delete[] ArreJug;
  ArreJug = new Seleccion [Sel2.NumJug]; // <<---
}

If ArreJug is of type Jugador* ... Why do you make a reservation type Seleccion[] ? Seleccion[] will create a sequence of objects of type Seleccion ( see example ):

struct A
{
  A(){ std::cout << "A::A()\n"; }
};

struct B : A
{
  B(){ std::cout << "B::B()\n"; }
};

int main()
{
  A* lista = new B[3];

  // delete[] lista; // lo omito a propósito
}

As you can see in this example, calling new B[3] creates 3 objects of type B ... but the program understands that lista will store objects of type A ... if A and B do not have the same size this causes misalignment, which degenerates into unexpected behaviors :

struct A
{
    A(int x) : x(x) { }

    int x;
};

struct B : A
{
    B() : A(1), y(2) { }

    int y;
};

int main()
{
  A* lista = new B[3];

  std::cout << lista[0].x << lista[1].x << lista[2].x;
}

And of course, this ends up negatively affecting the life cycle of the objects ... At the moment in which we have polymorphism it is necessary that the compiler create what are known as " vtables " or virtual tables. These tables allow to execute the virtual methods that have been overwritten in child classes ... if the data is not aligned the pointer where the vtable should be is not correct and from there the program starts doing strange things:

struct A
{ };

struct B : A // No hay metodos virtuales = no hay vtable
{ };

struct vA
{
  virtual ~vA(){ }
};

struct vB : vA // metodos virtuales = hay vtable
{ };

int main()
{
  std::cout << sizeof(B) << '\n'
            << sizeof(vB) << '\n';
}

In my case the program prints the following:

1
8

As soon as there is a virtual method, we see how the class size increases to be able to contain the corresponding pointer to the virtual table. The byte occupied by the class without virtual methods is merely symbolic (the class is empty and 1 byte is the minimum unit of information).

So if you change the construction of the array to:

if ( NumJug != Sel2.NumJug )
{
  delete[] ArreJug;
  ArreJug = new Jugador[Sel2.NumJug];
}

you will get the program, at least in that part, to work correctly.

    
answered by 16.05.2017 / 09:11
source