Problemilla con C++

elkaoD

Bueno, por fin me estoy poniendo a aprender C++. Estoy haciendo una clase de vectores, pero tengo un problema. La clase tiene los miembros x, y, z a los que accedo con int getX() {return x;}. Entonces, cuando declaro un vector como const Vector3d ui(1,0,0); si uso ui.getX(); me dice "error: passing const Vector3d' asthis' argument of `float Vector3d::getX()' discards qualifiers", lo que no pasa si no declaro el vector como constante.

¿Por qué?

r2d2rigo

Norma de oro: cuando uses getters en C++, tienes que declararlos como metodo constante, que no es lo mismo que metodos que devuelven tipos constantes:

int getX() const
{
    return x;
}

Bienvenido al infierno...

elkaoD

Ahora me saltan otros errores:

In member function `float Vector3d::getLength() const':|
error: passing `const Vector3d' as `this' argument of `float Vector3d::operator*(Vector3d*)' discards qualifiers|
error: invalid conversion from `const Vector3d* const' to `Vector3d*'|
error:   initializing argument 1 of `float Vector3d::operator*(Vector3d*)'|

In member function `Vector3d Vector3d::getUnary() const':|
error: passing `const Vector3d' as `this' argument of `Vector3d Vector3d::operator/(float)' discards qualifiers|

El código de ambos métodos es:

    float getLength() const
    {
        return sqrt(this->operator*(this));
    }
    Vector3d getUnary() const
    {
        return this->operator/(this->getLength());
    }

Otra cosa, tengo una clase Cube tal que así:

class Cube
{
public:
    bool isVisible (int nface);

private:
    Vector3d vertex[8];

struct
{
    int d;
    Vector3d n;
} face[6];
};

isVisible es un método que devuelve true si la cara nface está mirando al observador (Un plano cuyo vector normal es j.)

bool Cube::isVisible (int nface)
{
    if (this->face[nface].n * uj > 0)
        return true;
    else return false;
}

Pues en isVisible me da estos errores:

In member function `bool Cube::isVisible(int)':|
error: no match for 'operator*' in '((Cube*)this)->Cube::face[nface].Cube::<anonymous struct>::n * uj'|
note: candidates are: Vector3d Vector3d::operator*(float)|
note:                 float Vector3d::operator*(Vector3d*)|

EDIT: Vale, lo del cubo es que la estructura no se puede acceder alegremente xD

r2d2rigo

Chacho postea el codigo directamente en pastebin y te lo corrijo yo, que te faltan mil consts por todos lados.

elkaoD

Ya, es lo que tiene estar aprendiendo a martillazos... Lo que subo que conste que está a medias, vamos, que sólo estoy proyectando las clases. Por ejemplo, getFace ni lo he hecho todavía (Ya verás tú mismo la cantidad de cagadas xD)

Por cierto, si ves algo hecho "raro", que conste que no es mi culpa, simplemente no sé que es lo mejor aún xD

http://pastebin.com/m6ecd21f5

Gracias.

r2d2rigo

Hecho y subido. Aunque no me acuerdo de las restricciones al usar operators, por eso algunos lo mismo siguen sin irte (*=,+=, etc). Luego te lo miro.

elkaoD

El uj no me lo estoy inventando, solo que está escondido xD

const Vector3d uj(0,1,0);

Ahora me tira más errores que antes :s

error: base operand of ->' has non-pointer typeconst Vector3d' muchos de ellos. Son cuando intento usar v->getX() y cosas así.

EDIT: Ah vale, que ahora accedo a ellos con . al pasarlos por referencia. No lo entiendo muy bien, la verdad.

r2d2rigo

Es lo malo de hacerlo a mano, que como he cambiado todos los parametros de * a const&, me he dejado la conversion de -> a . por el camino. Ahora si, lo he probado compilando y ya funciona todo.

Y si, es asi de confuso, pero esque no tienes que pasar los objetos como * a menos que vayas a modificarlos directamente dentro; es mejor pasarlos como const& para asi poder acceder a ellos sin el riesgo de modificarlos accidentalmente.

Ah, y en los operator* y operator/ te faltaba definirlos como metodos constantes, porque al devolver un objeto nuevo no modifican el propio.

Confuso, eh? :P

elkaoD

Ok, más o menos voy entendiendo. Una última cuestión, para hacer el getter de las caras del cubo, ¿Debería devolver las caras o la referencia a ellas?

r2d2rigo

Pues depende del uso que le quieras dar, pero yo te aconsejaria que devolvieras la referencia para evitar overheads y usar punteros directamente:

CubeFace* getFace(int n) const
{
    return &face[n];
}
elkaoD

Muchas gracias por la ayuda, parece que voy entendiendo, y va saliendo :) En cuanto a estructura de ficheros... ¿Debería hacer un .h con la clase en sí y un .c con los métodos?

r2d2rigo

Pues si, es lo mas indicado. Un .h con la definicion de la clase (y con guarda de inclusion por si acaso)

#ifndef _MICLASE_H_
#define _MICLASE_H_

// ... codigo ...

#endif

y un .cpp con los metodos rellenados. Si quieres por facilidad puedes declarar algunas funciones inline en el propio .h, mientras no ocupen mas de 2 o 3 lineas.

elkaoD

Venga, última pregunta por hoy, lo prometo xD

Veamos, tengo una clase Cube que contiene 6 CubeFace. Uno de los métodos de CubeFace (Método update) recibe tres vectores y forma un plano con ellos que se guarda en CubeFace. El problema es el siguiente: para saber qué vectores son los que le tengo que pasar al método update, tengo que guardar tres vértices (Como número de vértice, no como vector) de la cara en CubeFace. Sin embargo, los vértices como vectores los tengo en Cube, que es la clase que contiene los CubeFace, así que no puedo acceder desde CubeFace a al Cube que lo contiene para hacer getVertex(numero_vector). ¿No?

Supongo que simplemente estoy diseñando mal las clases, pero por si acaso...

Lo de los ficheros... ¿Debería hacer en main un #include "vectors.c" y dentro de vector.c un #include "vectors.h" o cómo?

Puni

lo que incluyes son siempre las declaraciones de las clases, es decir los .h
piensa q include no es un import ni algo sofisticado, es como copypastear el codigo tal cual
en el main harias un include de vectors.h y en el propio vectors.c tb

r2d2rigo

Y por que no defines un array de vertices y otro de indices en la clase Cube y pasas de usar CubeFace? Seria mas facil. Porque o haces eso o le metes un puntero parent a las CubeFaces y terminas de liarla del todo :P

Y lo otro seria como dice #14, tu solo pones el #include de vector.h en vector.cpp y en main.cpp y el linker ya se encargara de ponerlo todo en orden.

elkaoD

Porque me gustaría abstraer las caras del cubo para poder tratarlas como vector normal + constante de forma más simple. Al final he decidido hacer que el constructor de cada cara reciba tres argumentos, el índice de los vértices, y que la cara sólo guarde el índice.

Ahora el problema es que no sé cómo inicializar dinámicamente el array de caras para pasarle los argumentos al constructor.

r2d2rigo

Comor? Explicate con lo de las caras :P

elkaoD

Es que estoy tratando las caras como planos, es decir, como un vector normal y una constante que cumplen Ax+By+Cz+D=0 porque me viene mejor para luego hacer cálculos con los planos. La clase Cara tiene un constructor tal que así Cara::Cara(int v1, int v2, int v3) que son los índices de los vértices del cubo (Del 0 al 7) en los que se apoya esa cara. El problema es que como declaro las caras como un array de Cara y el constructor necesita argumentos (No tiene un constructor por defecto) solo que no sé cómo pasárselos. Al final he dejado un constructor normal que lo pone a 0 y los inicizalizo más tarde en el código.

Si trato las caras como una clase aparte, todo se me facilita, creo. Al menos es la forma más lógica que veo.

GaN2

Pardiez, otro insensato que quiere aprender C++!!! Yo estoy recordando ahora al viejo enemigo en la universidad, por tema de una asignatura y cambio de profesor, hemos pasado de C# (que apesta) a C++, y raro es el día que no me quiero tirar por una ventana xD

Puni

#19 yo lo veia asi, pero quizas por buenos profesores o por gracia divina al final acabo gustandome en el sentido de q no me parecia raro ni nada. eso si, si no lo tienes dominado puedes volverte loco con los const y los &.

yo programando en c++ tengo q pensar mucho e ir poquito a poco, pensar si el metodo x es modificador o selector, si los parametros los pasas por copias, referencias o direccion, si necesitas o no un constructor de copia etc etc.

al final saque un 10 en las practicas y un 6.9 de 7 puntos del teorico de c++ (los otros 3 eran C y el ejercicio de la madre de todos los punteros xD)

pd: C++ fuck yeah! si entiendes codigo como este puedes conquistar el mundo
const string &getWord() const{return this->word;}

GaN2

Una duda rapida: para pasar de un int a un string???? Es que necesito pasarlo para utilizarlo en un método drawText() xD

cabron

#21:

stringstream cadena;
int numerito = 400;

cadena << numerito;

r2d2rigo

Y si por lo que sea no quieres usar strings...

int numero = 99;
char cadena[100];
sprintf(cadena,"%d",numero);
JuAn4k4

Entero a caracter:
http://en.wikipedia.org/wiki/Itoa

r2d2rigo

The itoa function is a widespread non-standard extension to the standard C programming language.

Pero no es estandar hamijoh :3

JuAn4k4

No he dicho que sea estandar, lo normal es que si la quieres usar, la pones como parte de tu codigo.

NeB1

cuanta razón en lo de "bienvenido al infierno"...

elkaoD

Una preguntita. Si yo en una clase, en el constructor reservo memoria dinámicamente y en el destructor la libero... ¿Al salir del programa se llama al destructor automáticamente, no? (A no ser supongo que también haya creado dinámicamente el objeto.)

cabron

#28:

Cuando un objeto sale de ámbito se llama a su destructor, vamos, que sí, es como dices.

r2d2rigo

#28: por norma, en los sistemas operativos modernos, en cuanto se finaliza un proceso de una manera u otra (ejecucion OK, kill, etc), se liberan todos los recursos asignados.