[comp.lang.c++] Need help, missing virtual tables, Sun C++ 2.0

mullens@jamsun.ic.ornl.gov (James A. Mullens) (05/09/91)

First, would anyone posting an answer also point me to a "frequently asked
questions" list and a Sun C++ 2.0 compiler bug list?

The problem is that the loader complains of undefined symbols such as
___vtbl__23SGob__BaseGob__ViewMngr__7WinMngr, meaning (I think) the virtual
function table for class WinMngr (a class derived from ViewMngr, BaseGob, and
SGob).  All modules compile without warnings, even with the "warn about
everything" flag turned on.  Only "vtbl" symbols are missing.  I believe I
am passing all modules to the loader, especially the WinMngr.o module.
I also deleted all object files and tried to rebuild the application from
scratch (just in case it was a makefile dependency problem) without luck.

I suspect that this has something to do with pure virtual functions.  On the
other hand, this version of the C++ compiler complains whenever a class tries
to inherit a pure virtual function -- I have no such warnings, and I have
no pure virtual specifications in any class I try to instantiate (WinMngr).
And the loader does not complain about every class I try to instantiate
(e.g. ViewMngr).

The only class using multiple inheritance is BaseGob (from SGob and Dynamic,
SGob is abstract and Dynamic is not).

Another thought has occurred to me.  The actual parentage of WinMngr is
Named -> SGob -> BaseGob -> ViewMngr -> WinMngr.  "Named" does not show up
in the vtbl (this is not too surprising since Named has no virtual
functions).  However, Named's child SGob is abstract whereas Named is not
abstract.  Could this be causing a problem?

One final thought... SGob, while abstract, has some static members and member
functions (accessors for the static members) which are called directly from
my main program.  Could this be causing a problem?

If no one has any hints for me I will try to construct a simple piece of code
that illustrates the problem and post it.

Thanks...

jim mullens
jcm@ornl.gov

siegel@cs.columbia.edu (David Siegel) (05/09/91)

I've been running into the same problems for the last two days.

Abstract classes appear to have something to do with the problem, as
making abstract classes concrete, and ensuring that all member functions
are actually implemented seems to help.

I'm _very_ interested in a definitive answer.

-dms

pal@xanadu.wpd.sgi.com (Anil Pal) (05/10/91)

In article <1991May8.224321.12580@cs.utk.edu>, mullens@jamsun.ic.ornl.gov (James A. Mullens) writes:
|> First, would anyone posting an answer also point me to a "frequently asked
|> questions" list and a Sun C++ 2.0 compiler bug list?

Sorry, I don't know where to find such a beast.  However, I will post an answer
regardless :-)

|> The problem is that the loader complains of undefined symbols such as
|> ___vtbl__23SGob__BaseGob__ViewMngr__7WinMngr, meaning (I think) the virtual
|> function table for class WinMngr (a class derived from ViewMngr, BaseGob, and
|> SGob).

The trick here is understanding where the translator puts the virtual
function table.  In order to reduce the number of copies of the virtual
function table, cfront-based translators (I believe Sun C++ 2.0 is one)
use the following strategy:

    The virtual function table for a class is output in a compilation
    stream if the compilation stream contains the *definition* for the
    first non-inline virtual function *declared* in that class.  Simple :-)

So, how do you use this information?  Well, look at the class in
question (and its base classes) and determine which is the first
non-inline virtual function declared (perhaps one of your base classes
has a virtual destructor?).  Then check to see that you have included
in your link the appropriate definition for that function in your
class.  In my experience, this is the most common cause of undefined
vtables at link time.  Note that if a pure virtual function is declared
in a derived class, it will not generate any warnings.  You may still
have forgotten to provide an implementation for a declared function,
and if no-one calls it, you will not be told that it is undefined.

-- 
Anil A. Pal,	Silicon Graphics, Inc.
pal@wpd.sgi.com	(415)-335-7279

philip@pescadero.stanford.edu (Philip Machanick) (05/11/91)

In article <1991May9.173442.5946@dragon.wpd.sgi.com> pal@xanadu.wpd.sgi.com
(Anil Pal) writes:
>The trick here is understanding where the translator puts the virtual
>function table.  In order to reduce the number of copies of the virtual
>function table, cfront-based translators (I believe Sun C++ 2.0 is one)
>use the following strategy:
>
>    The virtual function table for a class is output in a compilation
>    stream if the compilation stream contains the *definition* for the
>    first non-inline virtual function *declared* in that class.  Simple :-)
>
Consider a class with only inline virtual functions, like

class thing
{public:
  virtual void incr () {i++;}
private:
  int i;
};

When is the translator going to generate the virtual function table for this?
(Is it going to give up on trying to be optimal in this case and just generate
it in every file where the header is included?)

Philip Machanick

pal@xanadu.wpd.sgi.com (Anil Pal) (05/11/91)

In article <1991May10.182759.28323@neon.Stanford.EDU>, philip@pescadero.stanford.edu (Philip Machanick) writes:
|> Consider a class with only inline virtual functions.
|> 
|> When is the translator going to generate the virtual function table for this?
|> (Is it going to give up on trying to be optimal in this case and just generate
|> it in every file where the header is included?)

I believe so.  In addition, it will also generate non-inline copies of
the virtual functions (since it needs their address to put in the
virtual function table).  So, I would suggest that virtual
functions should not be made inline, since there is little chance that
the translator will actually inline them.  Note that it would need to
be able to bind the virtual function statically in order to inline it
(unless one considers some sort of switch statement with inline
function bodies).

This sort of thing (multiple static copies of virtual function tables and
non-inlined "inline" functions) can really increase the size of a program.

-- 
Anil A. Pal,	Silicon Graphics, Inc.
pal@wpd.sgi.com	(415)-335-7279

rfg@NCD.COM (Ron Guilmette) (05/12/91)

In article <1991May11.005908.22236@dragon.wpd.sgi.com> pal@wpd.sgi.com writes:
>In article <1991May10.182759.28323@neon.Stanford.EDU>, philip@pescadero.stanford.edu (Philip Machanick) writes:
>|> Consider a class with only inline virtual functions.
>|> 
>|> When is the translator going to generate the virtual function table for this?
>|> (Is it going to give up on trying to be optimal in this case and just generate
>|> it in every file where the header is included?)
>
>I believe so.

Something sounds wrong here.

If vtables have extern linkage (which they must if they are going to end
up being sharde in some cases across compilation units) and if you have
several of them (all presemably with the same name) then your going to
get "multiply defined" errors at link time, right?



-- 

// Ron ("Loose Cannon") Guilmette
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// New motto:  If it ain't broke, try using a bigger hammer.

pal@xanadu.wpd.sgi.com (Anil Pal) (05/14/91)

In article <5507@lupine.NCD.COM>, rfg@NCD.COM (Ron Guilmette) writes:
|> Something sounds wrong here. [ re: multiple copies of vtables ]
|> 
|> If vtables have extern linkage (which they must if they are going to end
|> up being sharde in some cases across compilation units) and if you have
|> several of them (all presemably with the same name) then your going to
|> get "multiply defined" errors at link time, right?

In the case where multiple vtables are generated, the generated vtable
name includes the name of the source file being compiled.  If you have
a cfront-based system, take a look at the generated code for a simple
case like:

	class foo {
	    virtual int f1()	{ return 1; }
	};

The possible existence of multiple virtual function tables makes using
vtable addresses as unique identifiers for a class (to provide runtime
type information, for example) a triccky problem.

-- 
Anil A. Pal,	Silicon Graphics, Inc.
pal@wpd.sgi.com	(415)-335-7279