Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - eferion

#611
en C:


int entero = 5;
float decimal = 10.44;
char* cad = "abcde";

char buffer[200];
sprintf( buffer, "%s %d - %f", cad, entero, decimal );


en C++:

Código (cpp) [Seleccionar]

int entero = 5;
float decimal = 10.44;
std::string cad = "abcde";

std::stringstream stream;
stream << cad << " " << entero << " - " << decimal;

std::string resultado = stream.str( );

#612
Tienes que desplazar los caracteres desde "descartar"+1 a strlen(digitos) una posición hacia la izquierda y con eso has eliminado el carácter deseado.

La forma de hacerlo... un while, un for... como más te guste.
#613
justamente son los mensajes de error los que indican qué ha sucedido.
#614
Cita de: amchacon en 31 Marzo 2014, 13:01 PM
Copia y pega la columna del excel en un txt.

PD: El excel es un formato de Microsoft office, tienes dos opciones:

- Estudiarte como esta estructurado. Y entonces lo lees a pelo con fread().
- Usar una librería de terceros que ya haya hecho ese trabajo por ti (desconozco si existe, pero no creo exista una gratis al ser un formato no-libre).

Microsoft tiene una API que permite leer y escribir en ficheros Excel, lo que pasa es que la que yo conozco está preparada para .NET. Desconozco si dispone de un homólogo para C o C++... eso si, con el wrapper adecuado se puede hacer funcionar en C++ nativo sin problemas.

Con respecto al formato... desde 2007 los formatos de excel cambiaron su extensión a xlsx. Este formato es, en realidad, un fichero comprimido (con zip creo recordar). En su interior se encuentran varios archivos xml que contienen los datos de la configuración del libro y del contenido de las diferentes hojas.
#615
Código (cpp) [Seleccionar]

class Base
{
  public:
    Base( )
    { std::cout << "Constructor BASE" << std::endl; }

    Base( const Base& otro )
    { std::cout << "Constructor copia BASE" << std::endl; }

    Base& operator=( const Base& otro )
    { std::cout << "Operador asignacion BASE" << std::endl; }
};

class Derivada : public Base
{
    Derivada( )
    { std::cout << "Constructor DERIVADA" << std::endl; }

    Derivada( const Derivada& otro )
    { std::cout << "Constructor copia DERIVADA" << std::endl; }

    Derivada& operator=( const Derivada& otro )
    { std::cout << "Operador asignacion DERIVADA" << std::endl; }
};

int main( )
{
  Derivada derivada; // Constructor por defecto
  std::cout << "---" << std::endl;
  Derivada derivada2( derivada ); // Constructor copia
  std::cout << "---" << std::endl;
  Derivada derivada3 = derivada; // Constructor copia
  std::cout << "---" << std::endl;
  Derivada derivada4 = Derivada( ); // Constructor por defecto
  derivada4 = derivada2; // Operador de asignacion
  std::cout << "---" << std::endl;
  Base base( derivada ); // Constructor copia

  Base* base2 = new Base( derivada ); // Constructor copia
  delete base2;

  return 0;
}


El constructor copia permite, como su nombre indica, crear una réplica del objeto original. Parece un tema trivial y sencillo. Lo que sucede es que con herencia la cosa se complica.

Los constructores y operadores, como habrás podido comprobar con el código anterior, no son heredables, es decir, si tu llamas al constructor copia de "Derivada", no se llama por defecto al constructor copia de "Base", sino a su constructor por defecto... y al utilizar el operador de asignación de "Derivada" no se llama al operador de asignación de "Base". Este mecanismo impide al código crear una copia completa de un objeto si la clase destino se corresponde con una de las clases padres de la clase original ( en el ejemplo tenemos una instancia de "Derivada" y la copiamos dentro de una clase "Base"... el resultado es que se copia solo la parte correspondiente a "Base" y se ignora el resto.

Es un efecto colateral del polimorfismo. Por eso, en entornos polimórficos se hace necesario utilizar un mecanismo diferente para realizar copias exactas de los objetos sin importar su tipo concreto. Me refiero a los patrones de clonación:

Código (cpp) [Seleccionar]

class Base
{
  public:
    Base( )
    { std::cout << "Constructor BASE" << std::endl; }

    Base( const Base& otro )
    { std::cout << "Constructor copia BASE" << std::endl; }

    Base& operator=( const Base& otro )
    { std::cout << "Operador asignacion BASE" << std::endl; }

    virtual Base* Clone( )
    { return new Base( *this ); }

    virtual void Comentar( )
    {std::cout << "Clase BASE" << std::endl;
};

class Derivada : public Base
{
    Derivada( )
    { std::cout << "Constructor DERIVADA" << std::endl; }

    Derivada( const Derivada& otro )
    { std::cout << "Constructor copia DERIVADA" << std::endl; }

    Derivada& operator=( const Derivada& otro )
    { std::cout << "Operador asignacion DERIVADA" << std::endl; }

    virtual Base* Clone( )
    { return new Derivada( *this ); }

    virtual void Comentar( )
    {std::cout << "Clase DERIVADA" << std::endl;
};

int main( )
{
  Base* base = new Derivada( );
  Base* base1 = base->Clone( );
  Base* base2 = new Base( *derivada );

  base1->Comentar( );
  base2->Comentar( );

  delete base;
  delete base1;
  delete base2;

  return 0;
}


Como se puede ver en el código anterior, al llamar al constructor copia de "Base", se crea invoca al constructor copia de "Base", y no al de "Derivada", por lo que el objeto final será de tipo "Base". Sin embargo, al llamar a "Clone", como éste es un método virtual, se llama a la versión de "Derivada", que sí que es capaz de crear un objeto copia de éste tipo.

Espero que con esto te haya terminado de resolver las dudas. Si no es así, sigue preguntando ;)

Un saludo.
#616
A ver.

Si tu tienes

Código (cpp) [Seleccionar]

class base
{
    public:
        base(){}
        ~base(){}
        void comunicar() { cout << "BASE!" << endl; }       
};

int main (){       
    base *miclase = new base;
    miclase->comunicar( );
    return 0;
}


La situación es clara, la salida por pantalla será "BASE!".

Si ahora hacemos:

Código (cpp) [Seleccionar]

class base
{
    public:
        base(){}
        ~base(){}
        void comunicar() { cout << "BASE!" << endl; }       
};

class derivada: public base {
    public:
        derivada() {}
        ~derivada(){}
        void comunicar() { cout << "DERIVADA!" << endl; } 
};
int main (){       
    base *miclase = new derivada;
    miclase->comunicar( );
    return 0;
}


La salida seguirá siendo exactamente la misma, ya que al no ser virtual la función, al hacer el cast a la clase base la función llamada será la de la clase base. Dicho de otra forma, cada clase tendrá su propia función "comunicar", aunque se trate del mismo objeto:

Código (cpp) [Seleccionar]

    derivada *miclase1 = new derivada;
    base* miclase2 = miclase1;

    miclase1->comunicar( );
    miclase2->comunicar( );


Salida:

DERIVADA!
BASE!


Tercer ejemplo:

Código (cpp) [Seleccionar]

class base
{
    public:
        base(){}
        ~base(){}
        virtual void comunicar() { cout << "BASE!" << endl; }       
};

class derivada: public base {
    public:
        derivada() {}
        ~derivada(){}
        void comunicar() { cout << "DERIVADA!" << endl; } 
};
int main (){       
    base *miclase = new derivada;
    miclase->comunicar( );
    return 0;
}


Ahora la salida por pantalla cambia a "DERIVADA!". La razón es que, al crear una instancia de derivada, el compilador sustituye la función "comunicar" de base con la correspondiente de la clase "derivada". Al declarar la función como virtual se obliga al compilador a comprobar posibles sustituciones de la función.

Cuarto ejemplo:

Código (cpp) [Seleccionar]

#include <iostream>
using namespace std;

class base {
    public:
        base(){ }
        ~base(){}
        base( const base& otro ) { cout << "copia BASE!" << endl; }
        virtual void comunicar() { cout << "BASE!" << endl; }       
};
class derivada: public base {
    public:
        derivada() {}
        ~derivada(){}
        derivada( const derivada& otro ) { cout << "copia DERIVADA!" << endl; }
        void comunicar() { cout << "DERIVADA!" << endl; } 
};                                                       
void punte( base* c ){c->comunicar();}
void refer( base &c ){c.comunicar();}
void valor( base c  ){c.comunicar();}                       

int main (){       
    derivada *miclase = new derivada;   
    punte(  miclase );     //puntero
    refer( *miclase );    //referencia
    valor( *miclase );   //valor

    delete miclase;
    miclase = NULL;                     
    cin.ignore();
    return 0;
}


Salida:


DERIVADA!
DERIVADA!
copia BASE!
BASE!


Al pasar la clase por valor se hace necesario crear una copia local de la clase. Dado que el argumento de la función es de tipo "base", se realizará una copia de "base", es decir, la copia perderá la herencia a "derivada" . Como se puede ver en el código, la función "comunicar" de "base" imprime "BASE!", por lo que el código cumple con lo que se le pide.
#617
Programación C/C++ / Re: C++ QR Code
30 Marzo 2014, 20:51 PM
Y que tal con un array??


int main ( )
{
    char *chars = " *";

    char qr[21][21];
    int num,c,i;


    srand(time(NULL));
    for(i=0;i < 21;i++){
    for(c=0;c < 21;c++)
    {
     num=rand()%(2);
     qr[i][c] == num;

     cout<<"QR["<< i << "]["<< c <<"] = ["<< chars[ num ] <<"]" <<endl;
     }}
system("pause");
return 0;
}
#618
Este ejercicio se basa en polimorfismo.

Cuando tu declaras un metodo como virtual y lo sobreescribes en una clase derivada, el compilador llamará automáticamente a la función de la derivada, aunque el puntero sea de la clase base.

En el caso de que pases la clase por valor se llama al constructor copia... y claro, el compilador no es tan listo y llama al constructor copia de la clase base. En este caso la clase base tiene su propia función y es la que acaba siendo llamada.
#619
en C++ la clase por defecto para almacenar cadenas de texto es la clase string. char* es un puntero. Los punteros simplemente "apuntan" a una posición de memoria, que es donde se almacena la información importante.

Los punteros permiten gestionar información de forma "remota":

Código (cpp) [Seleccionar]

int dato = 20;

// Declaras un puntero, pero no apunta a nada en concreto, no esta incializado
int* puntero1;

// Ahora puntero1 apunta al valor de dato, cualquier cambio en puntero1 modificara el valor de dato
puntero1 = &dato;

*puntero1 = 30;

std::cout << dato << endl; // imprime 30


En tu caso, los punteros no apuntan a nada en concreto, luego el programa te va a fallar.

Los constructores son funciones especiales que se llaman automáticamente cuando se crean instancias de los objetos.

Código (cpp) [Seleccionar]

class Objeto
{
  public:
    Objeto( )
    { std::cout << "Objeto creado" << std::endl; }
};

int main( )
{
  Objeto objeto;
  return 0;
}


Este programa tiene como salida:


Objeto creado


Porque al crearse la instancia "objeto", se llama al constructor de "Objeto" automáticamente y este es el que imprime el mensaje. Los constructores permiten inicializar los valores de la clase para evitar que ésta tenga valores no válidos.

Los constructores tienen más historia, pero es mejor ir poco a poco.

En cuanto a tu código, si no quieres usar strings y prefieres char* tienes dos opciones:

Código (cpp) [Seleccionar]

// Te permite almacenar una cadena de 19 caracteres máximo
// La memoria la libera el programa automaticamente
char cadena[20];

// Te permite almacenar una cadena de 19 caracteres,
// pero luego tienes que acordarte de liberar la memoria con delete
char *cadena = new char[20];


Aunque lo más práctico suele ser usar la clase string, ya que te permite obviar la gestión de la memoria ( que ya te tocará pegarte con ella en otras partes del código ).

Código (cpp) [Seleccionar]

string cadena;
cin >> cadena;


Y bueno, si puedo por la mañana te escribo más que me están metiendo prisa.

Un saludo.
#620
No mezcles C (los includes con .h) con C++ (los includes sin .h). O usas una librería o usas la otra, pero mezclar las dos no compensa y da problemas.

Estás presuponiendo que el usuario va a introducir dos números inferiores a 50 para crear la matriz... eso deberías protegerlo un poco.

Para rellenar la matriz casi sería más sencillo un bucle doble ( i, j ) para recorrer todo el rango de filasxcolumnas y preguntarle al usuario directamente por el valor de la celda i-j. Así te aseguras que no queden celdas sin valor asignado.

Con los dibujos que muestras, intuyo que el desplazamiento puede ser en horizontal y en diagonal... pero estaría bien aclarar ese concepto. Yo presupongo que es así.

La idea es sencilla. Para la primera columna, localiza la celda con el valor más bajo y te quedas con su fila. La recursividad consiste en una función que dada una fila y una columna, busque el valor más bajo en la columna siguiente para el rango de filas ( f-1, f+1) y vuelta a empezar hasta que llegues al final de la matriz.

La mejora es simplemente que si f-1 o f+1 se sale de la matriz entonces buscas en el otro extremo de la columna correspondiente.