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