Problemas del enlazador C ++ con método estático
-
06-07-2019 - |
Pregunta
Estoy escribiendo una clase Vector3D que llama a un método estático en una clase VectorMath para realizar un cálculo. Cuando compilo, obtengo esto:
bash-3.1$ g++ VectorMath.cpp Vector3D.cpp /tmp/cc5cAPia.o: In function `main': Vector3D.cpp:(.text+0x4f7): undefined reference to 'VectorMath::norm(Vector3D*)' collect2: ld returned 1 exit status
El código:
VectorMath.h:
#ifndef VECTOR3D_H
#include "Vector3D.h"
#endif
class VectorMath {
public:
static Vector3D* calculatePerpendicularVector(Vector3D*, Vector3D*);
static Vector3D* norm(Vector3D*);
static double length(Vector3D*);
};
VectorMath.cpp
#include "VectorMath.h"
Vector3D* norm(Vector3D* vector) { // can't be found by linker
// do vector calculations
return new Vector3D(xHead, yHead, zHead, xTail, yTail, zTail);
}
// other methods
Vector3D.cpp
#include "Vector3D.h"
#include "VectorMath.h"
// ...
// vector implementation
// ...
int main(void) {
Vector3D* v = new Vector3D(x, y, z);
Vector3D* normVector = VectorMath::norm(v); // error here
}
¿Por qué el enlazador no puede encontrar el método VectorMath :: norm
? A primera vista, pensaría que debería declarar una norma como esta:
Vector3D* VectorMath::norm(Vector3D* vector) {
pero eso tampoco ayuda ...
Solución
Te estás perdiendo esto:
//VectorMath.cpp
#include "VectorMath.h"
|
V - here
Vector3D* VectorMath::norm(Vector3D* vector)
{
...
}
La función norma
es parte de VectorMath ::
. Sin eso, solo tienes una función gratuita.
Esto es más sobre tu diseño, pero ¿por qué estás usando punteros para todo? Esto es mucho más limpio:
class VectorMath {
public:
static Vector3D norm(const Vector3D&);
};
Toma referencias, estás en C ++, así que no escribas código C. ¿Qué sucede cuando llamo a esto?
VectorMath::norm(0); // null
Se bloqueará, tienes que poner un cheque, en cuyo caso, ¿qué debería devolver? Todo esto se limpia utilizando referencias.
Además, ¿por qué no hacer que estos miembros de la clase Vector3D
?
Vector3D* v = new Vector3D(x, y, z);
v->norm(); // normalize would be better, in my opinion
Por último, apilar las cosas. Su código ahora tiene una pérdida de memoria:
int main(void) {
Vector3D* v = new Vector3D(x, y, z);
Vector3D* normVector = VectorMath::norm(v);
// delete v;
// ^ you're not deleting it!
}
Cámbielo a esto y use conceptos RAII :
int main(void) {
Vector3D v(x, y, z);
Vector3D* normVector = VectorMath::norm(v);
// delete v;
// ^ you're not deleting it!
}
Y al hacer que norma
sea una función miembro, terminas con el código muy limpio:
int main(void) {
Vector3D v(x, y, z);
Vector3D normVector(v.norm());
}
Sin punteros, sin filtraciones, todo sexy.
Otros consejos
No ha definido el método Vector3D :: norm
en VectorMath.cpp
. En su lugar, ha definido una función global llamada norma
. Lo que debe hacer es calificar el nombre del método en la definición:
Vector3D* Vector3D::norm(Vector3D* vector)
Vector3D* VectorMath::norm(Vector3D* vector) { // can't be found by linker
// do vector calculations
return new Vector3D(xHead, yHead, zHead, xTail, yTail, zTail);
}