From: nwatson@enuxha.eas.asu.edu (Nathan F. Watson)
Subject: BCC:  virtual function calls from constructor/destructor
Organization: Arizona State University
Date: Sun, 16 Aug 1992 09:01:35 GMT


I ran into a problem with virtual functions today when using my
new C++ compiler (Borland C++ 3.1).

The scenario is as follows:
   * classes A and B are defined, and B is derived from A;
   * A's constructor calls a virtual function A::vfunc().  B::vfunc()
     is also defined.

An unexpected (though perhaps not unreasonable) thing happens when I
try to construct an object of class B.  A::A() is called first, which
then calls the virtual function A::vfunc().  I would expect use of
B::vfunc().  However, A::A() calls A::vfunc().

Later in the program, I call vfunc() for an object of type B.  B::vfunc()
is used, as expected.

A quick look at the Borland C++ and Stroustrup books did not bring
enlightenment.  Is BCC behaving appropriately?  I suppose a call
to B::vfunc() within A::A() might not make sense because the B class'
portion of the object has not yet been constructed.  Does Stroustrup
specifically mention this case?

The following code and output illustrate the situation described above.
If you have any insight, please mail me at nwatson@enuxha.eas.asu.edu.
Thank you.


// ---------- try.cpp

#include <iostream.h>
#include <fstream.h>

static ofstream ostr;

class A {
      int dummy;
   public:
      virtual void vfunc();
   public:
      A();
      virtual ~A();
      void indirect_vfunc();      // Indirect call to vfunc().
};
void A::vfunc()
   { ostr << "A::vfunc()" << endl; }
A::A()
   { ostr << "A::A()" << endl; vfunc(); }
A::~A()
   { ostr << "A::~A()" << endl; vfunc(); }
void A::indirect_vfunc()
   { ostr << "A::indirect_vfunc()" << endl; vfunc(); }

class B : public A {
   public:
      void vfunc();
   public:
      B();
      ~B();
};
void B::vfunc()
   { ostr << "B::vfunc()" << endl; A::vfunc(); }
B::B() : A()
   { ostr << "B::B()" << endl; }
B::~B()
   { ostr << "B::~B()" << endl; }

int main(int, char *[])
{
   ostr.open("try.out");
   {
      ostr << "---------- try.cpp output" << endl;
      ostr << "*** Constructing a" << endl;
      A a;
      ostr << "*** Constructing b" << endl;
      B b;
      ostr << "*** a.vfunc()" << endl;
      a.vfunc();
      ostr << "*** b.vfunc()" << endl;
      b.vfunc();
      ostr << "*** a.indirect_vfunc()" << endl;
      a.indirect_vfunc();
      ostr << "*** b.indirect_vfunc()" << endl;
      b.indirect_vfunc();
      ostr << "*** End (destructors)" << endl;
   }
   ostr.close();
   return 0;
}

---------- try.cpp output
*** Constructing a
A::A()
A::vfunc()
*** Constructing b
A::A()
A::vfunc()              <---- call of B::vfunc() expected.  ERROR?
B::B()                        (It is true that "B" class not yet constructed.)
*** a.vfunc()
A::vfunc()
*** b.vfunc()
B::vfunc()              <---- B::vfunc() (calls A::vfunc()) called.
A::vfunc()
*** a.indirect_vfunc()
A::indirect_vfunc()
A::vfunc()
*** b.indirect_vfunc()
A::indirect_vfunc()     <---- indirect calls works.
B::vfunc()
A::vfunc()
*** End (destructors)
B::~B()
A::~A()
A::vfunc()              <---- Destructor also calls only A::vfunc().  ERROR?
A::~A()                       (It is true that "B" class has been destroyed.)
A::vfunc()



--
---------------------------------------------------------------------
Nathan F. Watson                             Arizona State University
nwatson@enuxha.eas.asu.edu                Computer Science Department
Newsgroups: comp.lang.c++