Como ya he comentado en otros hilos, estoy haciendo un juego al tiempo que aprendo C++, o viceversa ;).
Estoy siguiendo más o menos el famoso curso de http://c.conclase.net/curso/index.php pero, claro, me surgen algunas dudas que espero que me ayudéis a resolver ::).
Y para no crear un hilo cada vez que tenga una pregunta, las pondré todas aquí.
Empiezo por una sencilla:
¿Las Clases tienen algún máximo de memoria? ¿Tiene sentido que me cree una "superclase" que contenga todas las variables y funciones de mi programa, o me dará problemas de memoria y/o de rendimiento?
Gracias 8)
Una classe es lo mas parecido a una estructura en C, por lo tanto, yo no conozco que tenga 'limite' de memoria esceptuando el de la propia maquina (4Gb).
Lo que si que tiene limite de memoria es el stack que tienen los programas, o en ese cas tu programa, a la hora de definir variables 'globales' como se les suele llamar. En ese punto es donde entra la memoria dinamica, los new's, deletes y tal.
Yo si te tengo que recomendar algo, es todo lo contrario a los que estas haciendo o pensando. Piensa en fragmentacion, no hagas 1 clase, haz 10, y con el paso del tiempo veras cuales de esas classes puedes juntar. Pero lo mejor de ese metodo es que podras 'reutilizar' codigo. Cuanto mas grandes y mas cosas hacen las clases menos reutilizacion tienen.
Y si me permites darte un consejo en C++, acostumbrate desde el principio a definirle a cada una de las classes que hagas las siguientes funciones:
- constructor por defecto
- constructor copia
- destructor
- operador =
- operador ==
- operador <
Teniendo las classes definidas de esta manera y definiendo luego algunos 'consts' en funciones de Get(...), pasarte a utilizar las listas, vectores, maps de las STL sera casi transparente.
Un saludo y suerte
LLORENS
P.D: No olvides empezar por un juego sencillo
Cita de: tewe76 en 08 de Febrero de 2009, 03:34:22 PM
¿Tiene sentido que me cree una "superclase" que contenga todas las variables y funciones de mi programa, o me dará problemas de memoria y/o de rendimiento?
No. Una clase, una responsabilidad (http://en.wikipedia.org/wiki/Single_responsibility_principle). No necesariamente por motivos de rendimiento, sino de buen diseño.
CitarLo que si que tiene limite de memoria es el stack que tienen los programas, o en ese cas tu programa, a la hora de definir variables 'globales' como se les suele llamar.
¿Y cuál es ese límite? ¿Depende de la máquina?
CitarYo si te tengo que recomendar algo, es todo lo contrario a los que estas haciendo o pensando.
Vale, creo que me he confundido ::)
Me da la sensación de que quería conseguir con Clases lo que se supone que hay que hacer con Namespaces. Mi idea era hacer una superclase que contuviese variables de otras subclases, para que todo en mi engine estuviese estructurado tal que:
" TWIrr.Debug.Texto.Info="Hola"; ", por ejemplo. Pero me da la sensación de que para éso lo que tengo que usar son namespaces, con los que conseguiré algo similar:
" TWIrr::Debug::Texto::Info="Hola"; "
¿Es así como se hace? (Entendéis mi objetivo, ¿no?)
CitarY si me permites darte un consejo en C++,
No te permito, sino que te insto a que me lo des ;)
Citaracostumbrate desde el principio a definirle a cada una de las classes ...
Sí, el cons y el des ya lo estaba haciendo. Lo demás no porque aún no sé lo que son ::)
CitarP.D: No olvides empezar por un juego sencillo
Bueno, considero que mi "juego sencillo" es en sí el "miniengine sobre IrrLicht" que me servirá de base para el "juego grande". Me salto pasos porque soy nuevo en C++, pero no en la programación de juegos :).
CitarNo. Una clase, una responsabilidad. No necesariamente por motivos de rendimiento, sino de buen diseño.
Sí, si en realidad estoy aplicando ese concepto. Me expliqué mal, porque no pretendía hacer UNA SOLA clase con todo, sino una CLASE MADRE que contuviese un montón de subclases.
Bueno, como he metido mucho rollo, os recuerdo mi nueva pregunta actual: para lo que quiero, lo que tengo que usar son namespaces, ¿no?
Mi querido tewe estas preguntas son muy generales.
Tendras que leer mas teoria y veras que solas se disipan.
Segun lo que leo aun no has captado el paradigma de la programacion orientada a objetos.
Thinking in C++
Te puede ayudar con eso.
En teoria no deberias tener datos estaticos salvo puntuales exepciones, y pensar el desarrollo en objetos.
Tengo el PDF de "Thinking in C++" y le echo vistazos, pero no me gustaría aprender C++ en plan: "hale, voy a leerme un libro de 800 páginas" (aunque no niego que quizá fuese buena idea ::))
Justamente mi idea es preguntar cosas "generales", en el sentido de que no es cuestión de buscar una palabra en google y ya está, sino conceptos, usos generales, consejos, etc.
Volviendo a mi pregunta:
- Mirando el código del IrrLicht, creo que usan ese sistema de namespaces: tienen un namespace "irr" en el que declaran variables, funciones y también clases. Y, dentro de ese "irr" crean otros sub-namespaces ("core", "video", etc) con sus variables, etc. En principio me parece un método coherente.
- Sin embargo, mirando el código del Tetris de loover, no parece que use namespaces, sino básicamente clases con sus variables, funciones y objetos de otras subclases. Lo que no veo es que use una "Clase madre".
He implementado tanto una solución como la otra y funcionan ambas, y ambas me parecen coherentes, pero tengo que elegir una de ellas (y entender por qué unos usan una y otros usan otra). Sospecho que el motivo es simplemente que IrrLicht es un proyecto MUY complejo y el Tetris es bastante sencillo. Creo que esa es la diferencia, pero no lo sé.
¿Son correctas mis deducciones? Si ambos métodos son posibles, ¿cuál recomendáis?
Cita de: arkangel2803 en 08 de Febrero de 2009, 03:55:09 PM
Y si me permites darte un consejo en C++, acostumbrate desde el principio a definirle a cada una de las classes que hagas las siguientes funciones:
- constructor por defecto
- constructor copia
- destructor
Aqui tambien pregunto yo, ¿para que sirve el constructor copia?, si con el base yo me arreglo, ¿para que quiero el copia con otros parametros?. No digo que no pueda ser util, pero si tengo:
Coche (potencia, velocidad, aceleracion)
¿para que quiero ademas?
Coche (potencia, velocidad, aceleracion, marcacoche,etc)
Supongo que dependiendo de lo que hagas podra ser de utilidad o no, ¿no?
Eskema: Me temo que se referia a un clone, un duplicado del objeto. Lo que no se si se refiere a hacer un "public obj* obj.clone()" o a "public obj(obj origen)". Para la primera aconsejo crear un constructor sin parametros privado, aunque puede q sea mejor la segunda.
Respecto al tema que comentas de usar namespaces o una clase con objetos de otras clases, que a su vez tengan objetos que referencien al debug en cuestion.....a mi me parece que depende mas de como sea la persona y de que lenguajes se venga........yo antes de empezar con java utilizaba la segunda (clases con objetos de otras clases...), pero en java me estoy acostumbrando a lo que serian los namespaces (llamados package) a crear singletones estaticos para ese tipo de servicios.
Cita de: tewe76 en 09 de Febrero de 2009, 12:12:19 PM
He implementado tanto una solución como la otra y funcionan ambas, y ambas me parecen coherentes, pero tengo que elegir una de ellas (y entender por qué unos usan una y otros usan otra). Sospecho que el motivo es simplemente que IrrLicht es un proyecto MUY complejo y el Tetris es bastante sencillo. Creo que esa es la diferencia, pero no lo sé.
¿Son correctas mis deducciones? Si ambos métodos son posibles, ¿cuál recomendáis?
Si son como los namespaces de C#, tus deducciones son correctas :) Los namespaces se usan para agrupar "cosas" que tienen una funcionalidad parecida de forma que luego sean más coherentes de usar y buscar. A mi me parece una buena norma el meter cada cosa en su namespace, aunque sea un proyecto pequeñito :)
Un saludo,
Vicente
Cita de: tewe76 en 09 de Febrero de 2009, 12:12:19 PM
Tengo el PDF de "Thinking in C++" y le echo vistazos, pero no me gustaría aprender C++ en plan: "hale, voy a leerme un libro de 800 páginas" (aunque no niego que quizá fuese buena idea ::))
Justamente mi idea es preguntar cosas "generales", en el sentido de que no es cuestión de buscar una palabra en google y ya está, sino conceptos, usos generales, consejos, etc.
Volviendo a mi pregunta:
- Mirando el código del IrrLicht, creo que usan ese sistema de namespaces: tienen un namespace "irr" en el que declaran variables, funciones y también clases. Y, dentro de ese "irr" crean otros sub-namespaces ("core", "video", etc) con sus variables, etc. En principio me parece un método coherente.
- Sin embargo, mirando el código del Tetris de loover, no parece que use namespaces, sino básicamente clases con sus variables, funciones y objetos de otras subclases. Lo que no veo es que use una "Clase madre".
He implementado tanto una solución como la otra y funcionan ambas, y ambas me parecen coherentes, pero tengo que elegir una de ellas (y entender por qué unos usan una y otros usan otra). Sospecho que el motivo es simplemente que IrrLicht es un proyecto MUY complejo y el Tetris es bastante sencillo. Creo que esa es la diferencia, pero no lo sé.
¿Son correctas mis deducciones? Si ambos métodos son posibles, ¿cuál recomendáis?
Estás poniendo en una balanza dos cosas que no se utilizan con el mismo fin. Los namespaces proporcionan un mecanismo de aislamiento del espacio de nombres global, lo cual es útil de cara a la organización lógica del código, y además ayuda a evitar conflictos de nombres. Especialmente en una librería, es buena práctica utilizar namespaces con criterio.
Pero el hecho de que utilices namespaces no tiene nada que ver, funcionalmente hablando, con la jerarquía de clases de tu código, que utilices una "clase madre", etc.
Cita de: arkangel2803 en 08 de Febrero de 2009, 03:55:09 PM
Y si me permites darte un consejo en C++, acostumbrate desde el principio a definirle a cada una de las classes que hagas las siguientes funciones:
- constructor por defecto
- constructor copia
- destructor
- operador =
- operador ==
- operador <
Teniendo las classes definidas de esta manera y definiendo luego algunos 'consts' en funciones de Get(...), pasarte a utilizar las listas, vectores, maps de las STL sera casi transparente.
No en todas las clases tiene sentido definir alguna o algunas de esas funciones. De hecho, en algunas clases tiene sentido hacer precisamente lo contrario.
Yo últimamente me había acostrumbrado (si se puede combinar "últimamente" y un tiempo pasado) a usar boost::noncopyable (http://www.boost.org/doc/libs/1_37_0/boost/noncopyable.hpp) para detectar errores en operador de asignación y constructor de copia no implementados.
<editando>
Por cierto, creo que nadie ha respondido al constructor de copia.
Puedes leer en el tutorial de c.conclase (http://c.conclase.net/curso/index.php?cap=029) lo que es. No es lo mismo copiar un objeto que crear uno nuevo mediante un constructor con una determinada signatura.
En resumen, hace falta cuando copiar los atributos no funciona (comportamiento por defecto). Por ejemplo, cuando tienes un puntero al que le pertenece la memoria, es decir, que va a ser liberado al destruir un objeto, dejando al otro (que al ser copiado apunta al mismo sitio) en un estado de error. En lugar de copiar el puntero, se quiere copiar el contenido del puntero. No es el 100% de los casos de punteros, en otros sí se quiere copiar el puntero, porque la memoria no pertenece al objeto.
CitarRespecto al tema que comentas de usar namespaces o una clase con objetos de otras clases, que a su vez tengan objetos que referencien al debug en cuestion.....a mi me parece que depende mas de como sea la persona y de que lenguajes se venga........
CitarSi son como los namespaces de C#, tus deducciones son correctas Los namespaces se usan para agrupar "cosas" que tienen una funcionalidad parecida de forma que luego sean más coherentes de usar y buscar. A mi me parece una buena norma el meter cada cosa en su namespace, aunque sea un proyecto pequeñito
CitarEstás poniendo en una balanza dos cosas que no se utilizan con el mismo fin. Los namespaces proporcionan un mecanismo de aislamiento del espacio de nombres global, lo cual es útil de cara a la organización lógica del código, y además ayuda a evitar conflictos de nombres. Especialmente en una librería, es buena práctica utilizar namespaces con criterio.
Pero el hecho de que utilices namespaces no tiene nada que ver, funcionalmente hablando, con la jerarquía de clases de tu código, que utilices una "clase madre", etc.
Vuestras respuestas son un poco incoherentes entre sí, pero creo que todos venís a decir, más o menos, que namespaces y clases no son incompatibles, que cada uno sirve para lo suyo, y que ambos son convenientes. Así pues, mi conclusión (ahora ::)) es que sí tiene sentido crear una clase madre, pero entonces volvemos a la duda original:
¿Es bueno crear una clase enorme (en cuanto a memoria, no en cuanto a miembros)? arkangel2803 ha dicho que no hay límite de tamaño para las clases, pero sí para las variables globales. Y, obviamente, si creo una clase madre es para crear una variable global de esa clase ???Pensaba que la pregunta era sencilla, pero veo que se complica, y no lo entiendo...
¿Vosotros no usáis un método tipo "Juego -> Render -> Dibujar" (es un ejemplo, no lo toméis al pie de la letra)? ¿Cómo lo implementáis?
A ver, un ejemplo que lo mismo te ayuda:
- Un namespace es una agrupación de CLASES que tienen un sentido en la vida similar. Es como la agrupación de contenidos que haces tu en tu ordenador con las carpetas: Mis Documentos tiene ficheritos de texto, Mi Musica mp3s, etc etc.
- Una clase madre es simplemente una forma de agrupar código que es común a un conjunto de clases. Tu en Mis Documentos tienes muchos documentos diferentes: PPTs de chorradas, CVs, cartas,... Y puede que para escribir cartas siempre uses una plantilla especial de carta y luego la modifiques para cada carta en concreto, esa plantilla sería como la superclase que contiene las cosas comunes de todas las demás cartas (que serían lo que se llama la especialización de la superclase).
Espero que te ayude a entender la diferencia entre para que vale una cosa y para que vale la otra, pero seguro que hay ejemplos mejores :p
Un saludo!
Vicente
Según donde declares el objeto o como instancies la clase, se reservará memoria en el heap, en el stack o en el segmento de datos (new/malloc, variables locales, variables globales). La pila y el segmento de datos tienen máximos con los que no es bueno jugar, por si cambiamos de arquitectura y la cosa deja de ir. El máximo que puedas reservar en el heap dependrá de la RAM que tengas libre y de lo fragmentada que esté.
De todas formas esa clase madre de la que hablas, pues no debería de ser más que un conjunto de punteros a los diferentes subsistemas de los que contará tu juego (lógica, vídeo, audio, ...) y un puñado de métodos. Así que no tendría que ocupar ni unos centenares de bytes de esos que te preocupan tanto.
Cita de: tewe76 en 10 de Febrero de 2009, 12:00:04 PM
¿Es bueno crear una clase enorme (en cuanto a memoria, no en cuanto a miembros)? arkangel2803 ha dicho que no hay límite de tamaño para las clases, pero sí para las variables globales. Y, obviamente, si creo una clase madre es para crear una variable global de esa clase ???
No es bueno tener clases enormes, ni depender de variables globales. Principalmente porque dificulta el uso y mantenimiento del código. Respecto al tamaño, como se ha comentado, si tienes una clase que contiene varios subsistemas como miembros, normalmente no los almacenas por valor, estáticamente, sino que mantienes punteros (inteligentes) a los mismos.
Cita de: tewe76 en 10 de Febrero de 2009, 12:00:04 PM
Pensaba que la pregunta era sencilla, pero veo que se complica, y no lo entiendo...
¿Vosotros no usáis un método tipo "Juego -> Render -> Dibujar" (es un ejemplo, no lo toméis al pie de la letra)? ¿Cómo lo implementáis?
Como lo implementes depende de muchas cosas. Pero siguiendo tu ejemplo, podrías tener algo como (muy a grosso modo, y con omisiones):
class IRenderer
{
public:
void Render()
{
BOOST_FOREACH(boost::shared_ptr<IRenderable> renderable, renderable)
{
renderable->Render();
}
}
private:
std::vector<boost::shared_ptr<IRenderable> > renderables;
};
class Game
{
public:
void Render() { renderer->Render(); }
private:
boost::shared_ptr<IRenderer> renderer;
};
Puedes ver que abunda la semántica de referencia, el tamaño no debería ser un problema en la mayoría de casos.
CitarUna clase madre es simplemente una forma de agrupar código que es común a un conjunto de clases.
Seguramente mi expresión no es correcta, pero no me refería a una clase básica común de la que hereden las demás, sino a una clase desde la cual se accede a las demás.
CitarDe todas formas esa clase madre de la que hablas, pues no debería de ser más que un conjunto de punteros a los diferentes subsistemas de los que contará tu juego (lógica, vídeo, audio, ...) y un puñado de métodos. Así que no tendría que ocupar ni unos centenares de bytes de esos que te preocupan tanto.
CitarRespecto al tamaño, como se ha comentado, si tienes una clase que contiene varios subsistemas como miembros, normalmente no los almacenas por valor, estáticamente, sino que mantienes punteros (inteligentes) a los mismos.
Ah, punteros... como nunca los he usado ::), no los tomaba en consideración, pero tenéis razón en lo que decís.
CitarComo lo implementes depende de muchas cosas. Pero siguiendo tu ejemplo, podrías tener algo como (muy a grosso modo, y con omisiones):
No entiendo del todo el código, pero creo que capto la idea.
Gracias a todos :)
A ver, siguiendo el tetris de loover (anda que no le saco partido :P), he implementado lo que llevaba de mi engine y parece que funciona todo bien, pero os pongo un ejemplo simple de cómo lo hago para que me digáis si está bien:
class ClaseHija
{
public:
int DatoDeHija;
};
class ClaseMadre
{
public:
ClaseHija* HIJA;
};
int main()
{
ClaseHija MiHija; //creamos la Hija
ClaseMadre MiMadre; //creamos la Madre
MiMadre.HIJA=&MiHija; //"asociamos" el puntero de la Hija a la Madre
//Usos posibles:
//1:
MiMadre.HIJA->DatoDeHija=10;
//2:
MiHija.DatoDeHija=10;
}
(Nota: loover usa el constructor para hacer el "MiMadre.HIJA=&MiHija;", aunque a mí hacerlo así me resulta más intuitivo. Lo he probado de las dos formas y las dos van bien.)
Preguntas:
1- ¿Es correcto este método? Con que no sea una bestialidad me conformo ::)
2- Para acceder a DatoDeHija puedo usar cualquiera de los dos "Usos", ¿no? ("MiMadre.HIJA->DatoDeHija=10;" o "MiHija.DatoDeHija=10;")
Este ultimo post no lo entiendo....clase madre y clase hija se llama cuando hay HERENCIA, es decir, la clase hija HEREDA de clase madre. En tu ejemplo una de las clases tiene como variable un puntero a la otra clase.....
No entiendo ??? ???
Sobre las preguntas:
1- No es incorrecto (salvo que no entiendo el nombre de las clases)
2- Ambas son correctas. Lo mas normal es (en mi opinion) que tengas una clase principal con punteros a tus diferentes servicios(render, fisicas, etc, etc) y que tengas un puntero global a esta clase principal. Asi en el main la instancias y tienes acceso desde cualquier parte del proyecto.
Todo es correcto, pero yo no expondría públicamente un puntero tan alegremente, porque cualquiera es libre de hacer lo que quiera con él.
CitarEste ultimo post no lo entiendo....clase madre y clase hija se llama cuando hay HERENCIA, es decir, la clase hija HEREDA de clase madre. En tu ejemplo una de las clases tiene como variable un puntero a la otra clase.....
Ya, es que mi terminología es confusa :-[ . La llamo madre en el sentido de que contiene a todas las demás (como una nave nodriza contiene a las mininaves). En vez de Madre, llámala Primaria, y en vez de Hija, Secundaria.
Citar2- Ambas son correctas. Lo mas normal es (en mi opinion) que tengas una clase principal con punteros a tus diferentes servicios(render, fisicas, etc, etc) y que tengas un puntero global a esta clase principal. Asi en el main la instancias y tienes acceso desde cualquier parte del proyecto.
Es lo que estoy haciendo en el ejemplo EXCEPTO que para la clase principal uso un objeto, no un puntero al objeto (si es que te he entendido bien).
¿Qué ventaja tiene usar un puntero en vez de el objeto directamente? ???
CitarTodo es correcto, pero yo no expondría públicamente un puntero tan alegremente, porque cualquiera es libre de hacer lo que quiera con él.
¿Lo que propones es poner los punteros en el private (de Madre) y poner en el public (de Madre) unas funciones que devuelvan ese puntero privado? ¿Qué peligros puede tener dejar el puntero en public?
Cita de: tewe76 en 12 de Febrero de 2009, 11:54:16 AM
CitarEste ultimo post no lo entiendo....clase madre y clase hija se llama cuando hay HERENCIA, es decir, la clase hija HEREDA de clase madre. En tu ejemplo una de las clases tiene como variable un puntero a la otra clase.....
Ya, es que mi terminología es confusa :-[ . La llamo madre en el sentido de que contiene a todas las demás (como una nave nodriza contiene a las mininaves). En vez de Madre, llámala Primaria, y en vez de Hija, Secundaria.
Yo no escribiria el codigo de las clases hijas dentro de la clase madre si no cada clase en su propio archivo. Asi te resulta mas facil ver a simple vista que clases tienes en el proyecto y te ayuda a localizar con facilidad el codigo concreto que buscas. Para lo de la jerarquia Madre -> Hija usa lo de los namespaces y te quitas de rollos. Esto te permite tener inclusive el mismo nombre para algunas clases en diferentes ambitos: una clase "Buffer" en el nombre de espacios de "Graphics" y otra en "Audio" por ejemplo.
Cita de: tewe76 en 12 de Febrero de 2009, 11:54:16 AM
CitarTodo es correcto, pero yo no expondría públicamente un puntero tan alegremente, porque cualquiera es libre de hacer lo que quiera con él.
¿Lo que propones es poner los punteros en el private (de Madre) y poner en el public (de Madre) unas funciones que devuelvan ese puntero privado? ¿Qué peligros puede tener dejar el puntero en public?
Yo en C# no tengo punteros (gracias a Dios >:D) y esto lo solucione creando en la clase principal unas propiedades que devolvian la referencia a la instancia de la clase principal de cada area. Creo que en C++ se puede hacer igual, no?
Salu2...
Cita de: tewe76 en 12 de Febrero de 2009, 11:54:16 AM
CitarTodo es correcto, pero yo no expondría públicamente un puntero tan alegremente, porque cualquiera es libre de hacer lo que quiera con él.
¿Lo que propones es poner los punteros en el private (de Madre) y poner en el public (de Madre) unas funciones que devuelvan ese puntero privado? ¿Qué peligros puede tener dejar el puntero en public?
Para poder acceder a los miembros de la clase Madre desde una clase Hija puedes declararlos como protected, de esta forma seguirán siendo privados pero te permitirán no tener que crear las funciones que citas.
CitarYo no escribiria el codigo de las clases hijas dentro de la clase madre si no cada clase en su propio archivo.
No es eso lo que estoy haciendo. Cada clase está declarada y definida por separado, pero en la clase madre (voy a intentar llamarla primaria a partir de ahora, para evitar más confusiones) incluyo unos punteros a dichas clases secundarias.
CitarPara lo de la jerarquia Madre -> Hija usa lo de los namespaces y te quitas de rollos.
Sí, es lo segundo que intenté, y funcionaba también... no sé, le veo pros y cons a los dos métodos, tengo que pensarlo mejor...
CitarYo en C# no tengo punteros (gracias a Dios ) y esto lo solucione creando en la clase principal unas propiedades que devolvian la referencia a la instancia de la clase principal de cada area. Creo que en C++ se puede hacer igual, no?
No tengo la más remota idea ::) ;) Pero, ¿no me acabas de recomendar que use namespaces? ¿Para qué necesitas entonces clase principal?
CitarPara poder acceder a los miembros de la clase Madre desde una clase Hija puedes declararlos como protected, de esta forma seguirán siendo privados pero te permitirán no tener que crear las funciones que citas.
Ah, pensaba que te había entendido mal, pero eres tú el que me ha entendido mal a mí. Es que yo no quiero acceder a los miembros de la clase Madre desde una clase Hija (llamémoslas mejor Primaria y Secundaria), sino más bien al contrario: quiero que desde la Primaria pueda acceder a los datos de la Secundaria. Quiero y puedo, vamos, poniéndola en public me funciona bien.
Cita de: tewe76 en 12 de Febrero de 2009, 04:17:58 PM
CitarYo en C# no tengo punteros (gracias a Dios ) y esto lo solucione creando en la clase principal unas propiedades que devolvian la referencia a la instancia de la clase principal de cada area. Creo que en C++ se puede hacer igual, no?
No tengo la más remota idea ::) ;) Pero, ¿no me acabas de recomendar que use namespaces? ¿Para qué necesitas entonces clase principal?
Teweee, que son cosas diferenteeeeeeeeees y totalmente compatibles!
Sí, pero... -- da igual, me empieza a doler la cabeza ::)
Una clase principal para mi es una clase que gestiona operaciones de las anteriores y administra las copias e instancias que hagas de las hijas, por ejemplo, una clase principal de graficos, render o manager en mi caso, deberia ser quien gestione una coleccion de instancias de clases textura. La clase render o manager seria la clase madre del espacio de nombres de graficos y la clase textura seria una clase hija del espacio de nombres de graficos, una jerarquia, vamos. El espacio de nombres agruparia las clases pertenecientes a graficos y la clase madre seria el foco principal de operaciones del area de graficos.
CitarCitarPara poder acceder a los miembros de la clase Madre desde una clase Hija puedes declararlos como protected, de esta forma seguirán siendo privados pero te permitirán no tener que crear las funciones que citas.
Ah, pensaba que te había entendido mal, pero eres tú el que me ha entendido mal a mí. Es que yo no quiero acceder a los miembros de la clase Madre desde una clase Hija (llamémoslas mejor Primaria y Secundaria), sino más bien al contrario: quiero que desde la Primaria pueda acceder a los datos de la Secundaria. Quiero y puedo, vamos, poniéndola en public me funciona bien.
Si tienes una clase principal en el motor cuya instancia sea estatica (una clase estatica, vamos), esta la puedes acceder desde cualquier parte del codigo. Si en esa clase principal del motor tienes accesos definidos a las clases principales de las areas que defina el motor: graficos, audio, etc..., una clase textura podria acceder asi a las propiedades de la clase madre de graficos, aunque esto no deberia darse ya que la clase textura no deberia por que llamar a la madre, no se si me explico, seria la clase madre quien deberia tener acceso a las clases hijas, algo parecido a lo de programar por capas.
Estas historias de la POO tratalas con paciencia. Aqui donde me ves aun soy novato en este tipo de programacion (practicamente desde que toco .NET) y se que cuesta hacerse a ello despues de largos años programando en BASIC :P Con la practica es como veras las ventajas y los inconvenientes de hacer las cosas de una manera u otra.
Salu2...
Cita de: tewe76 en 12 de Febrero de 2009, 11:54:16 AM
¿Lo que propones es poner los punteros en el private (de Madre) y poner en el public (de Madre) unas funciones que devuelvan ese puntero privado? ¿Qué peligros puede tener dejar el puntero en public?
No necesariamente, depende de lo que necesites. Normalmente, si tienes:
struct Foo
{
Bar* bar;
};
Nada impide que, dado un objeto f de tipo Foo, alguien haga:
f.bar = NULL;
O algo igualmente peligroso. Peligroso porque rompe la invariante de tu clase (que bar apunte a un objeto de tipo Bar válido), y entre otras cosas te obliga a comprobar que bar es distinto de NULL cada vez que necesitas utilizarlo. Compáralo a:
class Foo
{
public:
Foo(Bar& b) : bar(&b) { }
const Bar& GetBar() const { return *bar; }
Bar& GetBar() { return *bar; }
private:
Bar* bar;
};
Por poner un ejemplo, aunque no es idiomático utilizar punteros llanos en C++. Dependiendo de si la clase en cuestión asume la propiedad exclusiva o compartida de la memoria que se le pasa, se utiliza un tipo de puntero inteligente u otro.
Cita de: tewe76 en 12 de Febrero de 2009, 11:54:16 AM
¿Qué ventaja tiene usar un puntero en vez de el objeto directamente? ???
¿Cómo es posible hacer referencia desde varias clases a un mismo objeto de otra clase sin utilizar punteros o referencias?
CitarEstas historias de la POO tratalas con paciencia.
En éso estamos... ::)
A davur:
Me temo que mi nivel de C++ no me permite entenderte ::) . El problema sí lo entiendo, aunque no lo veo muy preocupante. Y la solución la capto a nivel general, pero no consigo implementarla.
Si os parece bien, por mi parte cierro ya el tema de Clases, Namespaces y similares. Por ahora voy a usar el método que he explicado en el ejemplo, que me va bien y es bastante intuitivo :) .
Seguro que vuelvo pronto con más dudillas. Taluego ;)
Maldita sea, tewe, léete el libro de 800 páginas y deja de enredar. Tardarás mucho menos en volver con las preguntas realmente interesantes.
Autoconsejo para no volver a perder unas horas buscando el problema ::) :
- Si el programa te hace cosas raras, borra las carpetas de Debug y Release para que lo compile todo desde cero, porque es probable que haya quedado algo corrupto.
Ay, lo que tiene aprender a golpes ^_^'
Cita de: tewe76 en 19 de Febrero de 2009, 12:12:51 PM
Autoconsejo para no volver a perder unas horas buscando el problema ::) :
- Si el programa te hace cosas raras, borra las carpetas de Debug y Release para que lo compile todo desde cero, porque es probable que haya quedado algo corrupto.
Más fácil: dale a "Rebuild Solution/Project" o su equivalente en español que no recuerdo. Él solito te borra todo eso para que no lo tengas que hacer tú :).
"Generar - Limpiar Solución" creo que es lo que dices, también lo he probado y parece que va :)
Sactamente, es eso. Por cierto, cuando vaya creciendo el proyecto no te recomiendo darle si no es estrictamente necesario... yo más de una vez (y más de n también) le he dado por error a ése en vez de al que te compila sólo lo que se ha modificado, y la broma me hace perder como 10 minutos recompilando todo el maldito proyecto :P
Citary la broma me hace perder como 10 minutos recompilando todo el maldito proyecto
En ese caso deberían poner un mensaje de confirmación, porque sí que es un fastidio, sí ::)
Cita de: tewe76 en 19 de Febrero de 2009, 05:12:14 PM
Citary la broma me hace perder como 10 minutos recompilando todo el maldito proyecto
En ese caso deberían poner un mensaje de confirmación, porque sí que es un fastidio, sí ::)
Los atajos de teclado son tus amigos ;)
Cita de: Vicente en 19 de Febrero de 2009, 06:18:43 PM
Cita de: tewe76 en 19 de Febrero de 2009, 05:12:14 PM
Citary la broma me hace perder como 10 minutos recompilando todo el maldito proyecto
En ese caso deberían poner un mensaje de confirmación, porque sí que es un fastidio, sí ::)
Los atajos de teclado son tus amigos ;)
Sí que lo son. El problema es no acostumbrarse a usarlos en lugar del ratón de una puñetera vez :P
Cita de: Vicente en 19 de Febrero de 2009, 06:18:43 PM
Cita de: tewe76 en 19 de Febrero de 2009, 05:12:14 PM
Citary la broma me hace perder como 10 minutos recompilando todo el maldito proyecto
En ese caso deberían poner un mensaje de confirmación, porque sí que es un fastidio, sí ::)
Los atajos de teclado son tus amigos ;)
El problemas es acordarte de los atajos de un ide cuando estas con otro :S:S:S
Esta pregunta debe de ser tonta tonta, pero no encuentro la respuesta...
¿Hay en C++ alguna orden para salir inmediatamente de la aplicación? Si estás en Main, basta con poner "return", pero ¿si estás en otra función? En VB, por ejemplo, con End sale de la aplicación, estés donde estés. ¿Hay algo equivalente en C++?
Cita de: tewe76 en 26 de Febrero de 2009, 07:55:58 AM
Esta pregunta debe de ser tonta tonta, pero no encuentro la respuesta...
¿Hay en C++ alguna orden para salir inmediatamente de la aplicación? Si estás en Main, basta con poner "return", pero ¿si estás en otra función? En VB, por ejemplo, con End sale de la aplicación, estés donde estés. ¿Hay algo equivalente en C++?
http://c.conclase.net/librerias/funcion.php?fun=exit :) Es herencia del C, por cierto
Ah, ya veo, no forma parte del "núcleo" de C. Pues entonces me surjen preguntas sobre estas librerías estándar (hasta ahora no las había tocado ::) , justamente por las dudas :P)
Dudas:
1- ¿Todas las librerías estándar de C++ son las que salen en http://c.conclase.net/librerias/index.php ("Librerías : assert, ctype, errno, float, limits, locale, math, setjmp, signal, stdarg, stddef, stdio, stdlib, string y time") o hay más?
2- ¿Todas están disponibles en todos los IDEs?
3- ¿Todas son multiplataforma?
Creo que tengo más dudas, pero dejémoslo por ahora, que no quiero agobiaros ;)
Cita de: tewe76 en 26 de Febrero de 2009, 12:28:20 PM
1- ¿Todas las librerías estándar de C++ son las que salen en http://c.conclase.net/librerias/index.php ("Librerías : assert, ctype, errno, float, limits, locale, math, setjmp, signal, stdarg, stddef, stdio, stdlib, string y time") o hay más?
2- ¿Todas están disponibles en todos los IDEs?
3- ¿Todas son multiplataforma?
1- No. Hay más (http://www.google.es/url?sa=t&source=web&ct=res&cd=8&url=http%3A%2F%2Fopenassist.googlecode.com%2Ffiles%2FC%252B%252B%2520Standard%2520-%2520ANSI%2520ISO%2520IEC%252014882%25202003.pdf&ei=loKQSfX8KoS2jAem7f27Cg&usg=AFQjCNG4-cbawIu_O0_KwFqjXU6VG1cZDA&sig2=71L_wchYv0htx0nlPr220g).
2- Existen varias implementaciones completas de la librería estándar para diferentes arquitecturas (por ejemplo, Visual Studio utiliza Dinkumware (http://www.dinkumware.com/)).
3- La librería estándar es, bueno, estándar. Salvando los puntos que el estándar del lenguaje reserva explícitamente a la implementación de la librería, del código que utiliza la librería estándar precisamente se espera un comportamiento independiente de la plataforma.
Gracias, davur :)
La 2 y la 3 las tengo claras, pero de la 1... entiendo que hay más, pero no sé qué se supone que es el PDF que linkas (¿una especie de normativa ISO para crear nuevas librerías estándar?)
Bueno, en http://msdn.microsoft.com/es-es/library/ct1as7hw.aspx creo entender que hay 52 libs de C++ y 18 de C.
El PDF es una copia del estándar de C++ vigente en la actualidad, y define los requisitos que deben cumplir las implementaciones del lenguaje y de la librería estándar para poder catalogarse como estándar (valga la redundancia).
Cita de: tewe76 en 26 de Febrero de 2009, 07:55:58 AM
Esta pregunta debe de ser tonta tonta, pero no encuentro la respuesta...
¿Hay en C++ alguna orden para salir inmediatamente de la aplicación? Si estás en Main, basta con poner "return", pero ¿si estás en otra función? En VB, por ejemplo, con End sale de la aplicación, estés donde estés. ¿Hay algo equivalente en C++?
¿Por qué quieres salir de tu aplicación desde otro lugar distinto del main?
Porque quiero crear una función FinalizarEngine() que se encargue de descargar todo, cerrar archivos, etc, y salir al SO.
Cita de: tewe76 en 01 de Marzo de 2009, 01:18:44 PM
Porque quiero crear una función FinalizarEngine() que se encargue de descargar todo, cerrar archivos, etc, y salir al SO.
#include "engine.h"
int main()
{
try
{
Engine engine(...);
engine.Run();
}
catch (const EngineException& e)
{
//...
}
} // --> en este punto, ya se ha llamado a Engine::~Engine()
Utiliza los constructores y destructores para reservar y liberar recursos, es la manera idiomática en C++. Ni llamar a std::exit() ni tener una función global que necesitas invocar explícitamente son buenas ideas para lo que quieres hacer.
No entiendo bien tu ejemplo ??? :
#include "engine.h"
int main()
{
try
{
Engine engine(...);
engine.Run();
}
catch (const EngineException& e)
{
//... ¿aquí qué se supone que va?
}
//¿Aquí ya se ha llamado a Engine::~Engine()? Sólo suponiendo que la condición para salir del gameloop sea la no existencia de engine, ¿no?
} // -> en este punto, ya se ha llamado a Engine::~Engine()
Es un ejemplo que no pretende sentar cátedra. La clase Engine inicializa lo que necesita en el constructor, y lanza una excepción en caso de error. Excepción que tratas en main() de la manera que consideras oportuna. Luego se ejecuta el bucle principal de la manera que consideras oportuna, y que acaba cuando consideras oportuno.
Lo importante aquí es que el destructor de Engine, que presumiblemente liberará toda una serie de recursos, se llama automáticamente cuando sales del ámbito de la variable local engine sin ningún esfuerzo adicional por tu parte.
Ah, vale, ahora ya te he entendido mejor :)
Buenas. Yo lo que he hecho es en mi clase de video (la q crea la ventana y maneja el bucle de control del juego) crearme una funcion con un acceso estatico (por lo q es accesible desde cualquier punto del proyecto/programa) que se encargue de dar fin al bucle de control. Seria algo como:
Video::run() {
...inicializacion de recursos, librerias, etc...
while (!finPrograma) {
Video::Logica();
Video::Dibujado();
}
...finalizacion de recursos, librerias, etc...
}
static Video::finalizarPrograma() {
finPrograma=true;
}