D
druberego
I read google and tried to find the solution myself. YES I do know that
you can get undefined references if you:
a) forget to implement the code for a prototype/header file item, or
b) you forget to pass all the necessary object files to the linker.
Neither of those are my problem. Please bear with me as the question
I ask is rather long and I think it's beyond a CS101 level of linker
stupidity. If it is a stupid CS101 mistake I'm making I'll be quite
surprised.
Some other items: I am compiling with -Wall and NO warnings are
given during the compilation stages.
I've known how to code in C++ since 1991 but this is the first project
where I ever used a pure abstract base class.
During linking I'm getting this: (Which by the way I wasn't getting a
week ago and I haven't changed the destructors in any of my files.)
jeffw@mail:Automatic$ make test
g++ -g -O3 -Wall -pipe -fpic -I/usr/share/qt4/mkspecs/linux-g++
-I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4
-o test test.o libgeometry.a -lm -L/usr/lib64/qt4 -lQtGui -L/usr/lib64
-L/usr/lib64/mysql -L/usr/lib64/qt4
test.o.data.rel.ro+0x0): undefined reference to `vtable for Segment'
libgeometry.a(Line.o): In function `~Segment':
/home/jeffw/Automatic/Segment.hpp:43: undefined reference to `vtable
for Segment'
/home/jeffw/Automatic/Segment.hpp:43: undefined reference to `vtable
for Segment'
libgeometry.a(Line.o).data.rel.ro._ZTI4Line[typeinfo for Line]+0x10):
undefined reference to `typeinfo for Segment'
libgeometry.a(Edge.o): In function `~Segment':
/home/jeffw/Automatic/Segment.hpp:43: undefined reference to `vtable
for Segment'
/home/jeffw/Automatic/Segment.hpp:43: undefined reference to `vtable
for Segment'
collect2: ld returned 1 exit status
Here's the command that created libgeometry.a:
ar rcs libgeometry.a Entity.o GeometricEntity.o Point.o Vector.o
Segment.o Line.o Ray.o Edge.o Circle.o Arc.o Intersection.o
CNCProfile.o GlobalParameters.o
So yes, I do think I included Segment.o, Line.o and Entity.o which
shouldn't really matter since almost all of these include
Segment.hpp where the destructor body is actually defined.
What the heck does that mean??? Yes, I know it looks like I was
boob who forgot to implement a code body for a destructor. But
here's a couple of ideas.
The descended classes only contain primitive members or
members who's destructor can be the default destructor.
Since the class is provided with a default destructor doesn't that
mean I don't have to supply since all I would be doing is rewriting
the default anyways?
Second here's the slightly edited code for Segment.hpp
class Segment : public GeometricEntity
{
public:
static const unsigned char CONTINUES_BEFORE = 0x1;
static const unsigned char CONTINUES_AFTER = 0x2;
virtual ~Segment(void) {};
virtual Segment *clone(void) const = 0;
virtual Segment *clone(double beg, double end) const = 0;
virtual bool includes(const Point &p) const = 0;
virtual bool includes(double s) const = 0;
virtual bool isendpoint(double s) const = 0;
// functions for obtaining a point relative to the segment
//
virtual double scale(const Point &p) const = 0;
// Return a point relative to the endpoints.
// 0.0 = near end point
// 1.0 = the far end point as given to the constructor
virtual Point point(double scale) const = 0;
/* returns a list of scales relative to this, that identif
y the point
of intersection with the other segment */
virtual list<Intersection> intersect(const Segment *segmen
t) const = 0;
/* returns a list of scales relative to the other line, th
at identify
the points of intersection with this segment */
virtual list<Intersection> intersectwith(const Line &line)
const = 0;
/* returns a list of scales relative to the other Circle,
that identify
the points of intersection with this segment */
virtual list<Intersection> intersectwith(const Circle &cir
cle) const = 0;
virtual unsigned char relation(double s) const;
virtual std:stream &print(std:stream &o) const = 0;
virtual void draw(QPainter &qp, double diameter = 0.0) con
st = 0;
virtual std:stream &GCodeDepth(std:stream &o, double d
epth) const = 0;
friend std:stream &operator<<(std:stream &o, const Seg
ment *s);
}
Code for Segment.cpp
#include "Segment.hpp"
ostream &operator<<(ostream &o, const Segment *s)
{
return s->print(o);
}
Here's the code for Line.hpp
class Line : public Segment
{
protected:
Point p; // line parameters
Vector d; // direction of line, no other meaning
public:
Line(const Point &point, double radians)
: p(point), d(Vector(radians)) {};
Line(const Point &point, const Vector &direction)
: p(point), d(direction) {};
virtual Line *clone(void) const { return new Line(*this);
}
virtual Line *clone(double beg, double end) const;
virtual bool includes(const Point &point) const;
virtual bool includes(double) const { return true; }
virtual bool isendpoint(double) const { return false; }
// assuming that pnt lies on the line colinear with the se
gment,
// returns the value that would result in pnt = scale(valu
e) being
// true.
virtual double scale(const Point &pnt) const;
// return a point along the line colinear with this line s
egment.
// If 0<scale<1 then the point lines on the segment itself
..
// the vector D is scaled to obtain the point on the line.
virtual Point point(double scale) const;
/* returns a list of scales relative to this, that identif
y the point
of intersection with the other segment */
virtual list<Intersection> intersect(const Segment *s) con
st
{
// std::cerr << "determining intersection of Line wit
h ";
return s->intersectwith(*this);
}
virtual std:stream &print(std:stream &o) const;
virtual void draw(QPainter &qp, double diameter = 0.0) con
st;
virtual std:stream &GCodeDepth(std:stream &o, double d
epth) const;
virtual unsigned char relation(double) const
{ return Segment::CONTINUES_AFTER|Segment::CONTINUES_BEFOR
E; }
/* returns a list of scales relative to the other line, th
at identify
the points of intersection with this line */
list<Intersection> intersectwith(const Line &line) const;
/* returns a list of scales relative to the other Circle,
that identify
the points of intersection with this line */
list<Intersection> intersectwith(const Circle &circle) con
st;
Point P() const { return p; }
Vector D() const { return d; }
double distance(const Point &point) const;
friend std:stream &operator<<(std:stream &o, const Lin
e &l);
};
I'll avoid showing you Line.cpp because it's huge.
Now assume that I wasn't an idiot, everything that has a prototype
in Line.hpp HAS been implemented in Line.cpp.
There is NO definition of a ~Line() destructor ANYWHERE. I
shouldn't need one since the default is fine.
Why am I getting this linker error?????
And just to prove I'm not a total idiot...
This following little test program has the exact same architecture
and it compiles, links and runs just fine...
#include <iostream>
class Base
{
public:
virtual ~Base() {};
virtual int size() const = 0;
};
class Child : public Base
{
int s;
public:
Child(int ss) { s = ss; }
virtual int size() const;
};
int Child::size() const
{
return s;
}
int main(int argc, char *argv[])
{
Child t(56);
Base *b = &t;
std::cout << "Yeah, but I work just fine " <<
b->size() << std::endl;
}
Why won't my bigger program? And to top things off the version I
was working on a couple of weeks ago compiled and linked fine. I
made changes to member functions but didn't touch the
destructors AT ALL. And now it doesn't work.
The only thing I can think of is to rollback all my changes since a
commit of several weeks ago and start over. Because I think I'm
tripping a g++ bug here. The only thing I changed was code in
member functions. I didn't touch constructors, destructors or add
or remove any .h or .cpp files and this bug cropped up and I can't
make it go away. I mean look... Segment.hpp has a destructor
defined and coded, all of the classes either have a destructor
defined or I have not specified a destructor prototype and the
default should be fine and present.
Sigh...
you can get undefined references if you:
a) forget to implement the code for a prototype/header file item, or
b) you forget to pass all the necessary object files to the linker.
Neither of those are my problem. Please bear with me as the question
I ask is rather long and I think it's beyond a CS101 level of linker
stupidity. If it is a stupid CS101 mistake I'm making I'll be quite
surprised.
Some other items: I am compiling with -Wall and NO warnings are
given during the compilation stages.
I've known how to code in C++ since 1991 but this is the first project
where I ever used a pure abstract base class.
During linking I'm getting this: (Which by the way I wasn't getting a
week ago and I haven't changed the destructors in any of my files.)
jeffw@mail:Automatic$ make test
g++ -g -O3 -Wall -pipe -fpic -I/usr/share/qt4/mkspecs/linux-g++
-I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4
-o test test.o libgeometry.a -lm -L/usr/lib64/qt4 -lQtGui -L/usr/lib64
-L/usr/lib64/mysql -L/usr/lib64/qt4
test.o.data.rel.ro+0x0): undefined reference to `vtable for Segment'
libgeometry.a(Line.o): In function `~Segment':
/home/jeffw/Automatic/Segment.hpp:43: undefined reference to `vtable
for Segment'
/home/jeffw/Automatic/Segment.hpp:43: undefined reference to `vtable
for Segment'
libgeometry.a(Line.o).data.rel.ro._ZTI4Line[typeinfo for Line]+0x10):
undefined reference to `typeinfo for Segment'
libgeometry.a(Edge.o): In function `~Segment':
/home/jeffw/Automatic/Segment.hpp:43: undefined reference to `vtable
for Segment'
/home/jeffw/Automatic/Segment.hpp:43: undefined reference to `vtable
for Segment'
collect2: ld returned 1 exit status
Here's the command that created libgeometry.a:
ar rcs libgeometry.a Entity.o GeometricEntity.o Point.o Vector.o
Segment.o Line.o Ray.o Edge.o Circle.o Arc.o Intersection.o
CNCProfile.o GlobalParameters.o
So yes, I do think I included Segment.o, Line.o and Entity.o which
shouldn't really matter since almost all of these include
Segment.hpp where the destructor body is actually defined.
What the heck does that mean??? Yes, I know it looks like I was
boob who forgot to implement a code body for a destructor. But
here's a couple of ideas.
The descended classes only contain primitive members or
members who's destructor can be the default destructor.
Since the class is provided with a default destructor doesn't that
mean I don't have to supply since all I would be doing is rewriting
the default anyways?
Second here's the slightly edited code for Segment.hpp
class Segment : public GeometricEntity
{
public:
static const unsigned char CONTINUES_BEFORE = 0x1;
static const unsigned char CONTINUES_AFTER = 0x2;
virtual ~Segment(void) {};
virtual Segment *clone(void) const = 0;
virtual Segment *clone(double beg, double end) const = 0;
virtual bool includes(const Point &p) const = 0;
virtual bool includes(double s) const = 0;
virtual bool isendpoint(double s) const = 0;
// functions for obtaining a point relative to the segment
//
virtual double scale(const Point &p) const = 0;
// Return a point relative to the endpoints.
// 0.0 = near end point
// 1.0 = the far end point as given to the constructor
virtual Point point(double scale) const = 0;
/* returns a list of scales relative to this, that identif
y the point
of intersection with the other segment */
virtual list<Intersection> intersect(const Segment *segmen
t) const = 0;
/* returns a list of scales relative to the other line, th
at identify
the points of intersection with this segment */
virtual list<Intersection> intersectwith(const Line &line)
const = 0;
/* returns a list of scales relative to the other Circle,
that identify
the points of intersection with this segment */
virtual list<Intersection> intersectwith(const Circle &cir
cle) const = 0;
virtual unsigned char relation(double s) const;
virtual std:stream &print(std:stream &o) const = 0;
virtual void draw(QPainter &qp, double diameter = 0.0) con
st = 0;
virtual std:stream &GCodeDepth(std:stream &o, double d
epth) const = 0;
friend std:stream &operator<<(std:stream &o, const Seg
ment *s);
}
Code for Segment.cpp
#include "Segment.hpp"
ostream &operator<<(ostream &o, const Segment *s)
{
return s->print(o);
}
Here's the code for Line.hpp
class Line : public Segment
{
protected:
Point p; // line parameters
Vector d; // direction of line, no other meaning
public:
Line(const Point &point, double radians)
: p(point), d(Vector(radians)) {};
Line(const Point &point, const Vector &direction)
: p(point), d(direction) {};
virtual Line *clone(void) const { return new Line(*this);
}
virtual Line *clone(double beg, double end) const;
virtual bool includes(const Point &point) const;
virtual bool includes(double) const { return true; }
virtual bool isendpoint(double) const { return false; }
// assuming that pnt lies on the line colinear with the se
gment,
// returns the value that would result in pnt = scale(valu
e) being
// true.
virtual double scale(const Point &pnt) const;
// return a point along the line colinear with this line s
egment.
// If 0<scale<1 then the point lines on the segment itself
..
// the vector D is scaled to obtain the point on the line.
virtual Point point(double scale) const;
/* returns a list of scales relative to this, that identif
y the point
of intersection with the other segment */
virtual list<Intersection> intersect(const Segment *s) con
st
{
// std::cerr << "determining intersection of Line wit
h ";
return s->intersectwith(*this);
}
virtual std:stream &print(std:stream &o) const;
virtual void draw(QPainter &qp, double diameter = 0.0) con
st;
virtual std:stream &GCodeDepth(std:stream &o, double d
epth) const;
virtual unsigned char relation(double) const
{ return Segment::CONTINUES_AFTER|Segment::CONTINUES_BEFOR
E; }
/* returns a list of scales relative to the other line, th
at identify
the points of intersection with this line */
list<Intersection> intersectwith(const Line &line) const;
/* returns a list of scales relative to the other Circle,
that identify
the points of intersection with this line */
list<Intersection> intersectwith(const Circle &circle) con
st;
Point P() const { return p; }
Vector D() const { return d; }
double distance(const Point &point) const;
friend std:stream &operator<<(std:stream &o, const Lin
e &l);
};
I'll avoid showing you Line.cpp because it's huge.
Now assume that I wasn't an idiot, everything that has a prototype
in Line.hpp HAS been implemented in Line.cpp.
There is NO definition of a ~Line() destructor ANYWHERE. I
shouldn't need one since the default is fine.
Why am I getting this linker error?????
And just to prove I'm not a total idiot...
This following little test program has the exact same architecture
and it compiles, links and runs just fine...
#include <iostream>
class Base
{
public:
virtual ~Base() {};
virtual int size() const = 0;
};
class Child : public Base
{
int s;
public:
Child(int ss) { s = ss; }
virtual int size() const;
};
int Child::size() const
{
return s;
}
int main(int argc, char *argv[])
{
Child t(56);
Base *b = &t;
std::cout << "Yeah, but I work just fine " <<
b->size() << std::endl;
}
Why won't my bigger program? And to top things off the version I
was working on a couple of weeks ago compiled and linked fine. I
made changes to member functions but didn't touch the
destructors AT ALL. And now it doesn't work.
The only thing I can think of is to rollback all my changes since a
commit of several weeks ago and start over. Because I think I'm
tripping a g++ bug here. The only thing I changed was code in
member functions. I didn't touch constructors, destructors or add
or remove any .h or .cpp files and this bug cropped up and I can't
make it go away. I mean look... Segment.hpp has a destructor
defined and coded, all of the classes either have a destructor
defined or I have not specified a destructor prototype and the
default should be fine and present.
Sigh...