Anuncios Google

Definir una clase y/o funcion y usarla en una libreria C++

Clases y Librerias

Mi primer duda es con respecto a como definir una clase en c++ de manera que pueda ser usada en una libreria. Esto es lo que tengo:

class barra {
int x;
int y;
int mover();
int inicializar();
int mostrar();
};
 
//Lo que hago es lo siguiente
barra barra1;
 
int barra1::mostrar() {
lo que debe hacer
}

Eso es una version reducida, el problema es que al llamar la funcion desde el fichero cpp me dice que barra1 no es una clase, entonces, como puedo hacer que los atributos de la clase barra pasen a cada una de los que declare (barra1, barra2, etc...) sin declarar como clase a cada uno de ellos?

Otro problema que se me presenta es que si en el fichero .hpp defino por ejemplo

SDL_Surface *imagen_barra1;
 
int cargar_imagen() {
//Cargar imagen y almacenarla en imagen_barra1
}

Al querer llamar la funcion desde el cpp, me dice que no existe imagen_barra1, es decir, que no lo he declarado cuando en realidad lo hize dentro del fichero hpp, he estado leyendo un poco y creo que tengo que definirlo como "extern SDL_Surface *imagen_barra1"

Si alguien pudiera ayudarme con estos problemas estaria agradecido.

Disculpar si no he sido explicito y la falta de acentos, pero estoy en clase y debo hacer esto rapido o el profe me confizca la laptop :p

Saludos.


Anuncios Google

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de pspgorrister

C plus plus

Bueno, sobre el primer problema, aunque se pueda malhacer de otra forma, lo mejor es crear un ficheros independiente para la declaración de las clases, parece un trabajo extra, pero por la forma de trabajar que tiene C++ en las clases, ahorrá muchos problemas en cuando el proyecto empieze a crecer un poco.

barra.h

#ifndef BARRA_H
#define BARRA_H
 
class barra {
    private:
        int x;
        int y;
    public: //OJO!!!, por defecto los métodos son privados hay que poner esto para usarlos 
        int mover();
        int inicializar();
        int mostrar();
        //Usando estos 2 métodos creamos la "encapsulación" de no acceder directamente a las
        //variables internas del objeto, eso es un mal hábito y *NO* es programación orientada a obj.
       //Estas 4 funciones el compilador las creará "inline" por lo que se optimizan igual que modificar
       //directamente el valor de x e y
       int getX() {return x;}
       void setX(int xx) { x = xx;} 
       int getY() {return y;}
       void setY(int yy) { y = yy;}
};
#endif

 

barra.cpp

#include "barra.h"
 
//Aquí no hace falta usar variables, se usa directamente el nombre de la clase en el espacio de nombres
 
int barra::mostrar() 
{
    //lo que debe hacer
}
 
//Demás código de los otro métodos....

programa.cpp

#include "barra.h"
 
int main()
{
   barra barra1, barra2, barra3;
 
  //Un ejemplo, por poner algo... ;-)
   barra1.setX(3);
   barra1.setY(4);
   barra1.mostrar();
   return 0;
}

 

Tu segunda pregunta no la entiendo Pie en la boca


LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.

Imagen de burnxez

Segunda Parte

En cuanto a la segunda parte intentaré explicarlo lo mejor que pueda, en el fichero .hpp declaro cómo se cargará la imagen, doy donde se almacenará (SDL_Surface *imagen_barra1).

Sin embargo al cargar desde mi función main, (llamar a la función "cargar_imagen") me dice que imagen_barra1 no se ha definido, cuando ya estaba definido en el fichero .hpp, entonces, no está "conectando" las variables correctamente, pues aunque ya se definió, el compilador no se da cuenta de esto y me marca error.

Es lo mejor que puedo describirlo por ahora. Si aún no lo entiendes, colgaré el código, pero para eso necesito llegar a mi casa xD

Saludos.

PD:Diferencia entre .hpp y .h?

Imagen de pspgorrister

Sí, mejor con el código.

Sí, mejor con el código. pq no sé como está implementado eso que dices.

 

.hpp se usa a veces para los ficheros de cabecera de c++, yo suelo usar .h para ambos porque así nunca me lío cuando hago "include fichero.h", siempre sé que es .h. Es una cuestión más estética que otra cosa.


LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.

Imagen de burnxez

Dudas sobre teoria y otras cosas

Una pregunta sobre librerias, dentro de una libreria se puede hacer un include a otra?

Otra cosa, en tu ejemplo anterior veo que tienes 3 archivos:

  1. barra.h
  2. barra.cpp
  3. programa.cpp

Las funciones no se pueden definir dentro de la libreria barra.h?


Ahora, creo que mi segundo problema radica en que estoy trabajando con 2 librerias (relacionado a la pregunta anterior), en una defino clases y funciones de mis objetos, en la otra defino sólo funciones para hacer "x" cosa (cargar archivos, cargar fuente, cerrar fuente, etc...), el problema es que de la segunda libreria necesito hacer "includes" a la primer libreria por cuestiones de variables, creo que es aquí donde radica mi problema y lo estoy haciendo mal.

Bueno, creo que una salida del compilador te aclarará algunas cosas:

funciones.hpp: In function ‘bool cargar_archivos()’:                                            
funciones.hpp:98: error: ‘imagen_barra1’ no se declaró en este ámbito                           
funciones.hpp:99: error: ‘imagen_barra2’ no se declaró en este ámbito                           
funciones.hpp:100: error: ‘imagen_bola’ no se declaró en este ámbito                            
funciones.hpp:101: error: ‘imagen_fondo’ no se declaró en este ámbito  

                         
funciones.hpp: In function ‘void limpieza()’:                                                   
funciones.hpp:123: error: ‘imagen_barra1’ no se declaró en este ámbito                          
funciones.hpp:124: error: ‘imagen_barra2’ no se declaró en este ámbito                          
funciones.hpp:125: error: ‘imagen_bola’ no se declaró en este ámbito                            
funciones.hpp:126: error: ‘imagen_fondo’ no se declaró en este ámbito

Lo que me dice acerca de que no se ha definido, en realidad esta definido en la otra libreria (objetos.hpp) pero por alguna razón (mal diseño de mi parte, supongo) no las toma en cuenta.


Por último preguntarte si me recomiendas algún IDE pues "vim" no se me acomoda mucho para copiar/pegar código pero vaya que sus colores son chulos y funcionan de 10 :D


Saludos

PD:Por si te ayudara a aclarar algo, aunque supongo ya lo habras notado, estoy trabajando con C++ y SDL

Imagen de pspgorrister

Motivos para usar .h y

Motivos para usar .h y .cpp

-El compilador trata de forma diferente a los ficheros .h y los .cpp.

  • Lo que hay declarado en .h por defecto lo trata como una función "in line". Tema complejo, pero baste decir que no es nada recomendable hacerlo todo "in line", aunque es el compilador el que toma la decisión de hacerlo o no, según como se optimize.
  • Si se compila una clase (o lo que sea), sólo se genera el codigo de lo que hay en .cpp, el .h se queda sin compilar, esa es la parte que luego se "agrega" a la aplicación que la incluye.
  • De un vistazo al fichero .h se puede saber qué metodos/funciones tiene, sin entrar en detalles de la implementación del código. Para manejar una clase, sólo necesitamos saber sus métodos, no hace falta saber cómo funciona por dentro. Un fichero .h bien documentado ya vale igual que un manual de la clase

 

Tu problema según me cuentas es que haces "includes cruzados", eso es una jodienda que tiene C/C++, y hay que hacer un pequeño "truco",  ponerlo tanto en .h como en .cpp. Imaginemos miclase.h y funciones.h, funciones tienes un "#include miclase.h" y miclase. tiene un "#include funciones.h".

Nota: SIEMPRE en todos los .h, poner un "#ifndef", esto hace que sólo se haga un include durante el compilado, sino el compilador hace más de una vez el include y da error de que ya se usó ese .h

miclase.h

#ifndef MICLASE_H
#define MICLASE_H
#include funciones.h
 
//Aquí el código
 
#endif

funciones.h

#ifndef FUNCIONES_H
#define FUNCIONES_H
#include miclase.h
 
//Aquí el código
 
#endif

 

miclase.cpp

#include miclase.h
#include funciones.h
 
//Resto de código

funciones.cpp

#include funciones.h
#include miclase.h
 
//Resto de código

 


LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.

Imagen de burnxez

Avanzamos con esto de las librerias

Después de un rato, creo que ya he arreglado la mayor parte gracias a ti, tengo los ficheros .h, los .cpp y *casi* me compila bien. Ya no me tira las 500 lineas de errores por terminal que me tiraba antes, ahora sólo me tira 6, pero no entiendo muy bien cómo interpretarlas, copio/pego:

/tmp/cc7H8e16.o: In function `main':

pong++.cpp:(.text+0x549): undefined reference to `BarraI::iniciar()'
pong++.cpp:(.text+0x592): undefined reference to `BarraI::mover()'
pong++.cpp:(.text+0x5db): undefined reference to `BarraI::mostrar()'
pong++.cpp:(.text+0x624): undefined reference to `BarraD::iniciar()'
pong++.cpp:(.text+0x66d): undefined reference to `BarraD::mover()'
pong++.cpp:(.text+0x6b6): undefined reference to `BarraD::mostrar()'

collect2: ld devolvió el estado de salida 1

Bueno, la parte que no entiendo es esta "(.text+0xASD)" donde "ASD" es el número y/o letra que corresponde en cada caso.

Dejando esto de lado, creo que lo que estoy haciendo mal es definir las funciones dentro de mi fichero objetos.cpp el cual trabaja con la libreria objetos.hpp

//Dentro de objetos.h
 
class BarraI {
	private:
		int x;
		int y;
 
	public:
		int mover();
		int iniciar();
		int mostrar();
		int getX() {return x;}
		void setX(int xx) {x = xx;}
		int getY() {return y;}
		void setY(int yy) {y = yy;}
};

//Dentro de objetos.cpp
int BarraI::iniciar() {
	x = 0;
	y = (480 - imagen_barrai->h)/2;
	return 0;
}
 
int BarraI::mover() {
	if (KEYS[SDLK_UP]) {
		BarraI.sety (-=2);
	}
 
	if (KEYS[SDLK_DOWN]) {
		BarraI.sety (+=2);
	}
	return 0;
}
 
int BarraI::mostrar() {
	mostrar_superficie(BarraI.getx, BarraI.gety, imagen_barrai, pantalla);
	return 0;
}

//Dentro de fichero main
 
//Dentro de función main
 
//...Codigo...
 
BarraI barrai;
 
//...Un poco mas de codigo...
 
if (barrai.iniciar() == 1) {
		cout << endl << "Error al inicializar la barra 1" << endl;
 
		return 1;
	}
 
	if (barrai.mover() == 1) {
		cout << endl << "Error al mover la barra 1" << endl;
 
		return 1;
	}
 
	if (barrai.mostrar() == 1) {
		cout << endl << "Error al mostrar la barra 1" << endl;
 
		return 1;
	}
//...Sigue el codigo hasta la salida del programa...

Si he aplicado algo de los ejemplo que has dejado de manera erronea, te agradecería me dijeras para poder corregirlo.

Saludos.

Imagen de pspgorrister

Uhmm

Bueno, primero veo que tienes una  clase BarraI y otra BarraD, lo cual no hace falta. Haz una clase Barra y luego creas una variable objeto barrai (con posición a la izda.) y otra barrad (con pos a la dcha.). Pero dejando eso aparte.

-objetos.cpp, es muy genérico, hay que poner nombre_de_la_clase.cpp y nombre_de_la_clase.h, uno por clase. Si el error te lo diera en objetos.cpp te diría que te falta el "#include objetos.h", pero te lo da en pong++.cpp, así que deduzco que no es un fichero que contiene el código de la clase, en cuyo caso habría que usar la sintaxis BarraI.iniciar(), etc. Los dos puntos dobles "::" se usan para indicar que estás definiendo el método/función iniciar() se refiere a BarraI, que no es una función "suelta".


LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.

Imagen de burnxez

Casi compila

Tengo dos clases, izquierda y derecha, pues aún no se me ocurre cómo mostrar 2 imagenes con una sola clase, ahora hablando de mostrar imagenes, eso es lo que no me permite compilar.

Desde el problema anterior, simplemente hize un #include "barra.cpp" pues no lo tenia. Eso me llevo a declarar:

//Dentro de Barra.cpp
 
BarraI barrai;
 
BarraD barrad;

Los cambie de main() al fichero barra.cpp. Y a su vez cambie:

int BarraI::mostrar() {
	mostrar_superficie(BarraI.getx, BarraI.gety, imagen_barrai, pantalla);
	return 0;
}
 
//Cambiado por:
 
int BarraI::mostrar() {
	mostrar_superficie(barrai.getX, barrai.getY, imagen_barrai, pantalla);
	return 0;
}

esto a su vez, me llevo a otro error, copio/pego del compilador:

In file included from pong++.cpp:6:
objetos.cpp: In member function ‘int BarraI::mostrar()’:
objetos.cpp:19: error: el argumento de tipo ‘int (BarraI::)()’ no coincide con ‘int’
objetos.cpp: In member function ‘int BarraD::mostrar()’:
objetos.cpp:35: error: el argumento de tipo ‘int (BarraD::)()’ no coincide con ‘int’

A raíz de esto, lo volví a su estado anterior, pero me di cuenta que causa esto:

barra.cpp: In member function ‘int BarraI::mostrar()’:
barra.cpp:19: error: expected primary-expression before ‘.’ token
barra.cpp:19: error: expected primary-expression before ‘.’ token

De acuerdo a lo que he entendido con el final de tu comentario anterior, deduzco que lo correcto es dejarlo de esta forma:

int BarraI::mostrar() {
	mostrar_superficie(barrai.getX, barrai.getY, imagen_barrai, pantalla);
	return 0;
}

Bueno, entonces, esto causa que los argumentos no coincidan, la verdad es que para ser sincero no tengo ni idea a lo que se refiere, pues regresa 0 al final y tanto getX cómo getY son de tipo int.

Espero que no te hayas perdido al leer este comentario, que he tratado de hacerlo lo más claro posible.

Por cierto, si comento la función mostrar_imagen, compila sin problemas, pero obviamente no muestra imagenes, quiza esto debería (o más bien debo) hacerlo directamente desde main en lugar de declararlo en otro fichero, probaré y si obtengo algún resultado positivo o negativo lo posteo.

Saludos.

Imagen de pspgorrister

Buf, aquí tienes un lio de

Buf, aquí tienes un lio de clases y funciones.

Sobre " no se me ocurre cómo mostrar 2 imagenes con una sola clase". Estás un poco liado.

Tú te creas una clase barra, que tiene unos datos, digamos posX, posY, color, tamaño, etc.

Te creas 2 objetos barraizda y barradcha. de la clase barra:  barra barraizda, barradcha;

A cada una le asignas una posición, imagen que le correspone, y más datos si tuviera, ten en cuenta que la programación está dentro de las clases, son sus métodos los que tienen que hacer todo. Por ejemplo:

barra barraI, barraD;
 
barraI.setX(0);
barraI.setY(50);
barraI.setImage("barra_izda.png");
 
barraD.setX(300);
barraD.setY(130);
barraD.setImage("barra_dcha.png");
 
barraI.mostrar();
barraD.mostrar();

Ojo con el método barraI.setImage("barra_izda.png"), lo que tienes que hacer en el método setImage, es definirlo en .cpp, ya que es complejo y no se generará online, es crearte una SDL_Image a partir de ese fichero y lo guardas en un dato de la clase, por ejemplo m_SDLImage (yo uso m_ para diferenciar las variables miembro internas, pero eso es cuestión de estilo, usaría m_X, m_Y, etc.)

De tal forma que cuando llames al método mostrar(). usarías m_Image que ya contiene el SDL_Image, ahorrandote la función "mostrar_imagen", que en realidad es lo mismo que el método. y estás llamando a una función que envia como parámetro datos de un objeto que en realidad no te hace falta, porque eso mismo lo puedes hacer en el método mostrar. No sé si se me entiende.

 

Creo que el problema lo tienes porque usas funciones sueltas mezcladas con métodos y estas no pueden acceder a las partes privadas del objeto a no ser que las declares como friend. Pero en este caso, creo que es liarse, es mejor hacerlo todo en los método, no veo necesidad de poner funciones friend.

 

Siento no haberme explicado mejor. Un saludo

 


LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.

Imagen de burnxez

Petición

GorristeR, si tienes tiempo, te importaría poner un ejemplo de cómo cargarias tú una imagen, por que sinceramente, en estos momentos, estoy que no doy más, completamente liado, ya no encuentro pies ni cabeza a ninguno de mis ficheros, estoy tratando de hacer una combinación entre lo que tu me has dicho, los tutoriales de lazy foo, y el libro de Alberto Garcia Serrano, pero simplemente no se me da, cada vez termino con errores peores, uno trás de otro, intento basarme en sources de otros pero simplemente no me da el resultado esperado y termino liando más los ficheros, creo que iniciaré todo de 0 pues ya no le hayo forma a nada...

De cualquier forma, gracias por tu tiempo y ayuda, de verdad los aprecio.

Saludos.

Edito:

Después de dormir, irme a la escuela, y regresar a mi casa, me doy cuenta de que mis ideas ya están más ordenadas, y entiendo mis ficheros perfectamente, ya he comenzado la "remodelación" y creo que por fin he logrado "digerir" lo que me has dicho.

Gracias por todo!

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.