Foros - Stratos

Programadores => General Programadores => Mensaje iniciado por: davidgf en 21 de Noviembre de 2007, 09:29:58 PM

Título: #include y #ifndef
Publicado por: davidgf en 21 de Noviembre de 2007, 09:29:58 PM
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!
Título: Re: #include y #ifndef
Publicado por: TiRSO en 21 de Noviembre de 2007, 09:36:45 PM
Cita de: "davidgf"
#ifndef STREAMOGG_DEFINED
const int STREAMOGG_BUFFER_SIZE = 4096;

Ahí te falta un #endif. Supongo que será por eso.
Título: #include y #ifndef
Publicado por: davidgf en 21 de Noviembre de 2007, 09:55:05 PM
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...
Título: #include y #ifndef
Publicado por: Pogacha en 21 de Noviembre de 2007, 10:46:30 PM
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
Título: #include y #ifndef
Publicado por: davidgf en 21 de Noviembre de 2007, 10:57:54 PM
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
Título: #include y #ifndef
Publicado por: Pogacha en 21 de Noviembre de 2007, 11:27:08 PM
¿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.
Título: #include y #ifndef
Publicado por: davidgf en 21 de Noviembre de 2007, 11:34:31 PM
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!!!
Título: #include y #ifndef
Publicado por: Pogacha en 22 de Noviembre de 2007, 12:04:54 AM
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
Título: #include y #ifndef
Publicado por: TiRSO en 22 de Noviembre de 2007, 08:01:36 AM
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.
Título: #include y #ifndef
Publicado por: tamat en 22 de Noviembre de 2007, 11:51:48 AM
yo tambien creo que hay un ifndef que no está bien cerrado
Título: #include y #ifndef
Publicado por: Tei en 22 de Noviembre de 2007, 12:04:08 PM
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.
Título: #include y #ifndef
Publicado por: fiero en 22 de Noviembre de 2007, 12:35:03 PM
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
Título: #include y #ifndef
Publicado por: davidgf en 22 de Noviembre de 2007, 03:14:30 PM
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!!!!
Título: #include y #ifndef
Publicado por: shephiroth en 22 de Noviembre de 2007, 04:33:26 PM
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.
Título: #include y #ifndef
Publicado por: davidgf en 22 de Noviembre de 2007, 05:12:08 PM
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. ;)
Título: #include y #ifndef
Publicado por: fiero en 22 de Noviembre de 2007, 06:40:32 PM
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
Título: #include y #ifndef
Publicado por: shephiroth en 22 de Noviembre de 2007, 07:00:01 PM
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".
Título: #include y #ifndef
Publicado por: Pogacha en 22 de Noviembre de 2007, 09:37:36 PM
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.
Título: #include y #ifndef
Publicado por: davidgf en 24 de Noviembre de 2007, 01:37:05 AM
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....
Título: #include y #ifndef
Publicado por: Pogacha en 24 de Noviembre de 2007, 01:48:32 AM
Citaresto es culpa del catalán
... yo pensaba que escribias mal de simpatico tan solo :(
se me cayo un idolo.