Hola! Otra vez voi a dar guerra...
Pues mi marea sucia, guarra i tocina de programar (acostumbrado al VB) me a tocado las narices con los includes... i para evitar que se me includeen inifinitas veces le pongo a todos los headers un #ifndef #endif
Pero funciona con todos menos con uno... vaiaaa... Vosotros que le dais al c++ de verdad sabreis decir donde meto la pata:
cMusicEngine.cpp (clase que manda)
#include "cStreamOGG.h"
#include <dsound.h>
[...]
cStreamOGG.h (la clase que hace el trabajo sucio)
#ifndef CSTREAMOGG_H_INCLUDED
#define CSTREAMOGG_H_INCLUDED
#include "auxiliar.h"
#include "vorbis/codec.h"
#include "vorbis/vorbisfile.h"
#ifndef STREAMOGG_DEFINED
const int STREAMOGG_BUFFER_SIZE = 4096;
class cStreamOGG {
public:
[...] la clase continua
i en el codigo del cMusicEngine.cpp me dice que no encuentra la clase cStreamOGG, cuando uso un include bien grande hacia ella ademas de ponerle una proteccion para que no se incluya varias veces (porque hay muchos archivos que tienen muchos includes cruzados)
Alguna ayudita para un pobre ??? xD
Gracias!
Cita de: "davidgf"
#ifndef STREAMOGG_DEFINED
const int STREAMOGG_BUFFER_SIZE = 4096;
Ahí te falta un #endif. Supongo que será por eso.
Perdón, es que no he escrito pero al final hay dos #endif (uno para la inclusion del H i otro para la defincion de la clase)..
No se que puede ser...
Otra posibilidad de error, ya que dices que eres nuevo en C++, y pasa muy seguido es:
a.h#include "c.h"
class a {
f(c* _c) { _c->f(); }
};
b.h#include "a.h"
class b {
f(a* _a) { _a->f(); }
};
c.h#include "b.h"
class c {
f(b* _b) { _b->f(); }
};
main.cpp#include "a.h"
#include "b.h"
#include "c.h"
Result: Error class a undefined!
O bien te puede decir: tratando de usar la clase a la cual no esta definida. Si sigues el camino a.h -> b.h -> c.h -> skip a.h -> define class c -> use of a ( a has never been defined )
Lo escribi en un ciclo triple por que en uno doble se nota pero no se entiende.
Para solucionarlo se usa forward declarations.
Saludos
I como se hace eso?? Es que es muy muy raro... no entiendo porque pasa...
He probado a hacer lo de esta web http://www.adp-gmbh.ch/cpp/forward_decl.html pero nada... Sigue igual
¿En que archivo te dice que no se encuentra la clase?
Te tiene que decir elarchivo.h included in elcpp.cpp.
Te vas a ese .h y sacas el include .h donde esta la declaracion de la clase y dejas en su lugar class laclase;
Luego de esto en ese .h no podras usar esa clase, tan solo hacer referencia a punteros de la misma. Hacer Foo(laclase* a); en la cabecera y luego declarar la funcion en el cpp es valido pero no hacerlo inline tipo: Foo(laclase* a) { a->f(); }
Si hay constantes o definiciones involucradas las puedes sacar y poner en otra cabecera.
Muchas veces tienes que buscar como seria la mejor forma de hacerlo, para que te quede mas prolijo el codigo.
Ufff me cuesta de entender.
Me parece que mi estructura está mal. Yo tengo por cada clase un cpp con el codigo i la declaracion (metida entre ifndefs) i otro .h con la delcaracion de la clase solamente (metida tambien entre ifndefs)
Asi incluyo desde otro cpp o otro .h i la uso
Cómo debería ser el código? Todo .h? Cuando uso .h y cuando .cpp? QUe diferencia notable hay?
Mil gracias por tu ayuda Pogacha!!!
La palabra declarar se me confunde a mi tambien :oops:
la idea de como usar .h y .cpp
laclase.h
#ifndef LACLASE_H
#define LACLASE_H
#include "necesarios_para_esta_cabecera.h"
const tipo constante = valor;
class otra_clase_que_esta_definida_en_otro_h; // esto es un forward
class laclase {
tipo miembros;
public:
laclase();
~laclase();
void f(otra_clase_que_esta_definida_en_otro_h* p);
static void f2();
};
#endif
laclase.cpp
#include "laclase.h"
laclase::laclase()
: miembro(valor_por_defecto)
{
...
}
laclase::~laclase()
{
...
}
void laclase::f(otra_clase_que_esta_definida_en_otro_h* p)
{
p->Funcion_De_La_Otra_Clase();
}
void laclase::f2() // funcion estatica, miembro no es accesible ;P
{
...
}
En el h le dices al compilador como es la forma de la clase, ademas de constantes afines.
En el cpp le dices al compilador que hace la clase.
Esa es la idea.
En el .h puedes agregar funciones inline:
class laclase {
f(laotraclase* a) { a->f(); }
};
pero aqui es donde ese error sucede a veces entonces tienes que tener mucho ojo.
En el cpp no hay que poner el ifndef ni el define, esos son tan solo para el .h, en cada cpp se tienen que volver a leer los .h por eso es que los sacas a otro archivo, para compartir esa parte del codigo entre muchos cpps.
Saludos
EDITO:
En el .h va la declaracion y en el .cpp la implementación :P
Yo no entiendo para qué pones dos #ifndef anidados en el .h. No lo había visto en mi vida y en principio no creo que haga falta.
yo tambien creo que hay un ifndef que no está bien cerrado
No voy al problema, porque no se cual es.
Solo aporto un comentario.
En lugar de escribir esto:
Citar
#ifndef CSTREAMOGG_H_INCLUDED
#define CSTREAMOGG_H_INCLUDED
#include "auxiliar.h"
#include "vorbis/codec.h"
#include "vorbis/vorbisfile.h"
Puedes escribir esto:
Citar
#include "auxiliar.h"
#include "vorbis/codec.h"
#include "vorbis/vorbisfile.h"
#ifndef CSTREAMOGG_H_INCLUDED
#define CSTREAMOGG_H_INCLUDED
Ya que todos esos .h van a estar protegidos contra doble inclusión. No hace falta re-protegerlos dentro del ifndef.
Quizás puedas dibujar un arbolito de tus inclusiones. Para revelar un problema de definición circular como comenta un compañero.
Cita de: "davidgf"Ufff me cuesta de entender.
Me parece que mi estructura está mal. Yo tengo por cada clase un cpp con el codigo i la declaracion (metida entre ifndefs) i otro .h con la delcaracion de la clase solamente (metida tambien entre ifndefs)
Asi incluyo desde otro cpp o otro .h i la uso
Cómo debería ser el código? Todo .h? Cuando uso .h y cuando .cpp? QUe diferencia notable hay?
Hola David,
¿Dices que tienes en el CPP el código y la declaracion? ¿Y despues en el H solo la declaración?
Si has utilizado las mismas constantes CSTREAMOGG_H_INCLUDED en el CPP y en el H, seguramente la clase se haya incluido en el CPP, y luego el H se lo salta, por lo que ya no se declara la clase donde hayas incluido ese .H
Debes eliminar las declaraciones de los CPP. Para eso están los #include "fichero.h". Es cierto que se pueden declarar clases en cualquier sitio, pero si tienes poca experiencia, sigue siempre la norma: declaraciones en los .H y código en los .CPP
saludos
Vale! Ya lo he hecho y ha quedado todo bastante mejor.
Por cierto, reabro el tema del famoso "Mutithreaded Debug", esa opción del VS que hacía que Cal3D no me fuera bien y que consigue ahora que la version Release de mi juego no funcione. Si pongo en la lib del Cal3D "MT Debug" hasta ahora funcionava. Pero ahora al añadir OGG, si no añado MT Debug al proyecto principal no funciona.
Alguien abes porqué c**o no va???? Es una maldita opción al compilar!!!
Gracias a todos por la ayuda!! No si al final aprenderé i todo....
EDITO: AL final va TODO!!! Recompilé todo a saco desde 0. Ahora todo va correctamente!!! Weee!
Una preguntita de nada. Si uso Cal3D he hecho dos : la release i la debug. I a cada parte de mi juego le asigno una en las opciones del proyecto. Es necesario? o mi version debug puede ir con la release de Cal3D?? No se si lo he dicho bien...
I además es curioso poruqe el VS sabe donde estan los archivos i al debugear te entra automaticamente en los archivos de las DLLs que usas... Eso mola, pero lo hace siempre? Estoy flipando... Yo que pensava que el VS era cutrillo...
Millones de gracias a todos!!!!
Buenas.
Hace ya un tiempo que me he pasado a java (por la carrera) pero dentro de poco tendre que volver al c, asi que este tema me interesa. Ya que veo que mencionais las referencias circulares, me pregunto si esto funcionaria:
resuelve_circular.h:
#ifndef _CLASS_CIRCULAR_
#define _CLASS_CIRCULAR_
class a;
class b;
class c;
#endif
a.h:.
#include "resuelve_circular.h"
#ifndef _CLASS_A_
#define _CLASS_A_
class a{public b dameb();}
#endif
b.h:
#include "resuelve_circular.h"
#ifndef _CLASS_B_
#define _CLASS_B_
class b{public c damec();}
#endif
c.h:
#include "resuelve_circular.h"
#ifndef _CLASS_C_
#define _CLASS_C_
class c{public a damea();}
#endif
Y alla donde tengas que utilizar cualquiera de las clases incluir el .h auxiliar en vez de los .h de las clases directamente.
No lo se pero diria que no...
Yo he usado estas reglas:
Declarar en .h e implementar en cpp como me dijeron muy bien todos aqui.
En los .h (declaraciones) no incluir nada (que no sea string.h, windows... etc) y usar class LaClase; en vez de ello.
Luego en los cpp que usan las classes incluir los .h. Me parece que es mejor poner todos los includes en cada cpp (aunque te repitas)
I en los .h una proteccion para evitar la doble inclusion/declaración.
No se si me explico. Pero a mi me funciona; muy bien además. ;)
Cita de: "davidgf"I en los .h una proteccion para evitar la doble inclusion/declaración.
Mejor usa 'Y' griega, que algunos leemos foros en inglés y parece que estás todo el rato "Yo" "yo" "yo". Resulta bastante confuso :wink:
saludos
Cita de: "davidgf"No lo se pero diria que no...
Ok, pero si me dices pq no lo crees me servira de algo ^_^
Cita de: "davidgf"En los .h (declaraciones) no incluir nada (que no sea string.h, windows... etc) y usar class LaClase;
No se que profesor en su dia me dijo que en un .h incluir una cabecera del sistema (string.h, windows, etc...es decir, que no fuera propia del proyecto) es un error de 0.
No me quedo muy claro el tema, y cuando le pregunte tras terminar la clase me explico que el compilador (o mejor dicho el precompilador) siempre empieza a trabajar por los .cpp (o .c), y que si al llegar al .h no encuentra una clase es pq me falta el include en el .cpp nunca en el .h. Me explico tambien que incluir desde el .h puede llevar a errores bastante raros y dificiles de detectar.......intentare poner un ejemplo:
libreria_rara.h
#ifndef _LIBRERIA_RARA_
#define _LIBRERIA_RARA_
#ifndef _OPCION_EXTENDIDA_
#define OPT_DEBUG 0
#else
#define OPT_DEBUG 1
#endif
...resto de libreria
#endif
a.h
#ifndef _CLASS_A_
#define _CLASS_A_
#define _OPCION_EXTENDIDA_
#include libreria_rara.h
...resto de clase
#endif
principal.cpp
#include "windows.h"
#include "a.h"
//no definimos _OPCION_EXTENDIDA_ pq no queremos extension
#include "libreria_rara.h"
En este codigo se ve claro que habra que tener cuidado pq a.h define esa variable, pero hay ocasiones en las q no es tan claro ni tan "poco peligroso".
CitarEn los .h (declaraciones) no incluir nada (que no sea string.h, windows... etc) y usar class LaClase; en vez de ello.
Ojo, que esto es la mejor practica en teoria, permite una modulacion mayor y baja los tiempos de compilación, pero muchas veces no lo hacemos asi por temas de practicidad, especialmente cuando tenemos funciones inline, estructuras anidadas o clases principales como singletones u otras donde usar punteros no te serviría de mucho.
Tienes que buscar un equilibrio en compromiso entre las interrelaciones de los .h, prácticidad de escritura/lectura y funcionalidad del codigo.
Generalmente lo que se hace es separar en modulos y submodulos, de esta manera para cortar interdependencias entre inclusiones solo tienes que fijarte en pequeños sub modulos.
Esto se aprende con práctica, luego veras que ni bien te salte un error de este tipo ya vas a saber que paso y con poco podrás solucionarlo. Con el tiempo aprenderás a preverlo y no lo cometerás mas.
Cita de: "fiero"Cita de: "davidgf"I en los .h una proteccion para evitar la doble inclusion/declaración.
Mejor usa 'Y' griega, que algunos leemos foros en inglés y parece que estás todo el rato "Yo" "yo" "yo". Resulta bastante confuso :wink:
saludos
uups perdón... esto es culpa del catalán, luego escribo 'y' donde no toca i viceversa....
Citaresto es culpa del catalán
... yo pensaba que escribias mal de simpatico tan solo :(
se me cayo un idolo.