473,387 Members | 1,812 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

undefined reference to `vtable for Segment' due to virtual destructor???

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<Intersectionintersect(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<Intersectionintersectwith(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<Intersectionintersectwith(const Circle &cir
cle) const = 0;

virtual unsigned char relation(double s) const;

virtual std::ostream &print(std::ostream &o) const = 0;

virtual void draw(QPainter &qp, double diameter = 0.0) con
st = 0;

virtual std::ostream &GCodeDepth(std::ostream &o, double d
epth) const = 0;

friend std::ostream &operator<<(std::ostream &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<Intersectionintersect(const Segment *s) con
st
{
// std::cerr << "determining intersection of Line wit
h ";
return s->intersectwith(*this);
}

virtual std::ostream &print(std::ostream &o) const;

virtual void draw(QPainter &qp, double diameter = 0.0) con
st;
virtual std::ostream &GCodeDepth(std::ostream &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<Intersectionintersectwith(const Line &line) const;

/* returns a list of scales relative to the other Circle,
that identify
the points of intersection with this line */
list<Intersectionintersectwith(const Circle &circle) con
st;

Point P() const { return p; }
Vector D() const { return d; }

double distance(const Point &point) const;

friend std::ostream &operator<<(std::ostream &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...

Nov 20 '06 #1
5 11320
It took me a long time to copy the source files and
pair them down to the absolute minimum but I think
I found the answer...
(And I still sort of think it's a g++ bug)

I have it down to one very small file....

test.cpp
-----------------------------------
class Base
{
public:
virtual ~Base(void) {};

virtual unsigned char fun(void) const;
};

class Derived : public Base
{
public:
Derived() {}

virtual unsigned char fun(void) const;
};

unsigned char Derived::fun(void) const
{
return '\0';
}

int main(int argc, char *argv[])
{
Derived e();
}
----------------------------------

When compiled with
$ g++ test.cpp
/tmp/ccwHAAZy.o: In function `Base::~Base()':
test.cpp:(.text._ZN4BaseD2Ev[Base::~Base()]+0xd): undefined reference
to `vtable for Base'
/tmp/ccwHAAZy.o:(.rodata._ZTI7Derived[typeinfo for Derived]+0x10):
undefined reference to `typeinfo for Base'

Which is very similar to my original problem.

Now, Why do I think it's a g++ bug???
A couple of reasons:
1) The error message is misleading. It indicates that
the problem exists in Base::~Base(). which it
does not. The problem lies with the virtual fun()
method. (notice that I failed to provide a body for
fun() in the Base class. Which shouldn't matter
during linking time because I never call fun()
ANYWHERE.
2) There are multiple possible "fixes" and they don't
seem to be consistent In one incarnation I can
make the problem disappear by removing the
Base::~Base() definition entirely. (Though the
extremely short, single file version doesn't seem
to make a difference as it shouldn't.)

Fixes include:
A) specify the Derived::fun() body inline in the
class definition instead of as seperate code.
Huh??? how should that make a difference??
Except from inlining shouldn't the linker have to
link the same stuff and build all the same virtual
table stuff?? (Warning I know nothing about
implementing virtual functionality at the compiler
design level.)
B) Do the correct fix. Make the Base::fun() pure
virtual:
virtual unsigned char fun(void) = 0;

Basically, Isn't this a g++ bug? Should g++/linker warn
that it couldn't find a reference for Base::fun() instead of
complaining about Base::~Base()?

While I know it's wrong of me to neglect to provide a code
definition for anything why should it matter during linking
if Base::fun() is missing if it's never referenced anywhere?

Yes, I know I answered my original question but I sure
would like some insight into the questions the fix raised?

Nov 20 '06 #2
VJ
dr*******@gmail.com wrote:
Now, Why do I think it's a g++ bug???
A couple of reasons:
1) The error message is misleading. It indicates that
the problem exists in Base::~Base(). which it
does not. The problem lies with the virtual fun()
method. (notice that I failed to provide a body for
fun() in the Base class. Which shouldn't matter
during linking time because I never call fun()
ANYWHERE.
Yes, this error message is really stupid.
2) There are multiple possible "fixes" and they don't
seem to be consistent In one incarnation I can
make the problem disappear by removing the
Base::~Base() definition entirely. (Though the
extremely short, single file version doesn't seem
to make a difference as it shouldn't.)

Fixes include:
A) specify the Derived::fun() body inline in the
class definition instead of as seperate code.
Huh??? how should that make a difference??
Except from inlining shouldn't the linker have to
link the same stuff and build all the same virtual
table stuff?? (Warning I know nothing about
implementing virtual functionality at the compiler
design level.)
B) Do the correct fix. Make the Base::fun() pure
virtual:
virtual unsigned char fun(void) = 0;

Basically, Isn't this a g++ bug? Should g++/linker warn
that it couldn't find a reference for Base::fun() instead of
complaining about Base::~Base()?
That is the most obscure error message the gcc produces, but the reason
is usually simple:

The compiler has to put the vtable into an object file. It puts it into
the object file where the definition of the first non-inline member
function is. If it is missing, you get this rather unhelpful linker
error. Please check the existence of the definitions of your member
functions.

>
While I know it's wrong of me to neglect to provide a code
definition for anything why should it matter during linking
if Base::fun() is missing if it's never referenced anywhere?

Yes, I know I answered my original question but I sure
would like some insight into the questions the fix raised?
http://gcc.gnu.org/faq.html#vtables
Nov 20 '06 #3
VJ
dr*******@gmail.com wrote:
test.cpp
-----------------------------------
class Base
{
public:
virtual ~Base(void) {};

virtual unsigned char fun(void) const;
};

class Derived : public Base
{
public:
Derived() {}

virtual unsigned char fun(void) const;
};

unsigned char Derived::fun(void) const
{
return '\0';
}

int main(int argc, char *argv[])
{
Derived e();
}
----------------------------------
Sorry. I forgot the solution. Here it is:

unsigned char Base::fun( ) const
{
// want to do something?
}

Or make it pure virtual.
Nov 20 '06 #4
On 20 Nov 2006 02:19:56 -0800, I waved a wand and this message
magically appears in front of dr*******@gmail.com:
virtual unsigned char fun(void) const;
if you don't want to define a function for this; then do:

virtual unsigned char fun(void) const {};

*or*

virtual unsigned char fun(void) const = 0;

Easy.
--
http://www.munted.org.uk

You've been eating the cat food again, haven't you?
Nov 20 '06 #5
dr*******@gmail.com wrote:
int main(int argc, char *argv[])
{
Derived e();
}
In addition to the already answered questions about
the failure to fine Base::fun().. you do know that
the declaration in the main there defines a function
called e returning Derived (not a default constructed
Derived object called e)?
Nov 20 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Daniel Heiserer | last post by:
Hi, I got the following compiling/linking error, but I have no clue what it is about. Can anybody help me? thanks, daniel
20
by: qazmlp | last post by:
My class in a header file, contains inline virtual destructor. Is this Ok? Can it cause any problems? class base { public: base() { } virtual ~base { std::cout<<"Inside virtual destructor\n";...
2
by: Quansheng Liang | last post by:
Hello, I struggled with the problem of "undefined reference to `vtable ...`" while migrating a project from windows to linux. After searching the google I removed all the inline functions and now...
3
by: bp | last post by:
Hi, Could someone to tell me what I'm doing wrong? I'm using gcc version 3.3.4 and ld version 2.15.90.0.3 20040415 the linker message is: .../obj/classOpenAreaForm.o(.text+0x211): In...
7
by: Karl Ebener | last post by:
Hi! I have created a program using several classes with inheritage. When I compile and link, I get the following error: :$ g++ service2.cpp Service.cpp Application.cpp Message.cpp...
26
by: pmizzi | last post by:
When i compile my program with the -ansi -Wall -pedantic flags, i get this warning: `class vechile' has virtual functions but non-virtual destructor, and the same with my sub-classes. But when i...
4
by: Mark | last post by:
Hi, I'm trying to write some classes that kind of manage themselves. A linked list, that links different types of objects. Here's the code... object.h: --- class Object { int alt;
12
by: sojin | last post by:
Hi all, I'm a new to c++... and I've some doubts on "virtual" topics. 1) Can abstract base class have V-table? Here's the way,, Class CTemp{
8
by: lmfmaw | last post by:
Hi all, I've hit the wall with this "fairly" simple problem. As you can see in the code below, my destructors don't do their job as they are supposed to (I left them empty for this example). I'm...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.