g++: Too deep virtual inherance

Francois Bertel fbertel@irisa.fr
Thu Jan 13 06:21:00 GMT 2000


Compiler: g++
Versions: 2.91.66 and 2.95.2
System: Solaris
Command line: g++ -o test_virtual -Wall -ggdb -O0 virtual.cpp
The problem: g++ seems to have problem during construction when the
inherance is too deep and when this inherance is
virtual:
Result of ./test_virtual execution:
 0xffbef3e4 constructor without argument of class A
 --> 0xffbef3e8 constructor without argument of class B <--
Strange behavior
 0xffbef3f0 constructor of class C
 0xffbef3e0 constructor of class D
 d constructed
 0xffbef3d4 constructor without argument of class A
 0xffbef3d8 constructor of class B
 0xffbef3d0 constructor of class C
 c constructed
 0xffbef3d0 destructor of class C
 0xffbef3d8 destructor of class B
 0xffbef3d4 destructor of class A
 0xffbef3e0 destructor of class D
 0xffbef3f0 destructor of class C
 0xffbef3e8 destructor of class B
 0xffbef3e4 destructor of class A
The good behavior would be:
 0xffbef3e4 constructor without argument of class A
 --> 0xffbef3e8 constructor of class B <--
 0xffbef3f0 constructor of class C
 0xffbef3e0 constructor of class D
 d constructed
 0xffbef3d4 constructor without argument of class A
 0xffbef3d8 constructor of class B
 0xffbef3d0 constructor of class C
 c constructed
 0xffbef3d0 destructor of class C
 0xffbef3d8 destructor of class B
 0xffbef3d4 destructor of class A
 0xffbef3e0 destructor of class D
 0xffbef3f0 destructor of class C
 0xffbef3e8 destructor of class B
 0xffbef3e4 destructor of class A
This test shows that 'c' object construction is correct but not 'd'
object construction
The source code: just a file called virtual.cpp:
//*****************************************************************************
// File name: virtual.cpp
// Description: Test a possible bug in g++ about virtual inherance
//*****************************************************************************
// Version tested: 2.91.66 and 2.95.2
// Command line: g++ -o test_virtual -Wall -ggdb -O0 virtual.cpp
// Normal result:
// 0xffbef3e4 constructor without argument of class A
// --> 0xffbef3e8 constructor of class B <--
// 0xffbef3f0 constructor of class C
// 0xffbef3e0 constructor of class D
// d constructed
// 0xffbef3d4 constructor without argument of class A
// 0xffbef3d8 constructor of class B
// 0xffbef3d0 constructor of class C
// c constructed
// 0xffbef3d0 destructor of class C
// 0xffbef3d8 destructor of class B
// 0xffbef3d4 destructor of class A
// 0xffbef3e0 destructor of class D
// 0xffbef3f0 destructor of class C
// 0xffbef3e8 destructor of class B
// 0xffbef3e4 destructor of class A
// Bad result:
// 0xffbef3e4 constructor without argument of class A
// --> 0xffbef3e8 constructor without argument of class B <--
// 0xffbef3f0 constructor of class C
// 0xffbef3e0 constructor of class D
// d constructed
// 0xffbef3d4 constructor without argument of class A
// 0xffbef3d8 constructor of class B
// 0xffbef3d0 constructor of class C
// c constructed
// 0xffbef3d0 destructor of class C
// 0xffbef3d8 destructor of class B
// 0xffbef3d4 destructor of class A
// 0xffbef3e0 destructor of class D
// 0xffbef3f0 destructor of class C
// 0xffbef3e8 destructor of class B
// 0xffbef3e4 destructor of class A
// Bug: a too deep virtual inherance doesn't run correctly during
//      construction.
// Because: c construction is correct but not d construction
#include <iostream>
//*****************************************************************************
class A;
class B;
class C;
class D;
class A
{
public:
  //***************************************************************************
  // Constructors/Destructor
  //***************************************************************************
  //---------------------------------------------------------------------------
  // Name: A
  // Task: Constructor without argument
  //---------------------------------------------------------------------------
  explicit A(void);
  //---------------------------------------------------------------------------
  // Name: ~A
  // Task: Destructor
  //---------------------------------------------------------------------------
  virtual ~A();
};
//*****************************************************************************
class B
  : virtual public A
{
public:
  //***************************************************************************
  // Constructors/Destructor
  //***************************************************************************
  //---------------------------------------------------------------------------
  // Name: B
  // Task: Constructor without argument
  //---------------------------------------------------------------------------
  explicit B(void);
  //---------------------------------------------------------------------------
  // Name: B
  // Task: Constructor with the argument `a'
  //---------------------------------------------------------------------------
  explicit B(const int a);
  //---------------------------------------------------------------------------
  // Name: ~B
  // Task: Destructor
  //---------------------------------------------------------------------------
  virtual ~B();
private:
  //***************************************************************************
  // Implementation
  //***************************************************************************
  //---------------------------------------------------------------------------
  // Name: i
  // Description: an integer variable
  //---------------------------------------------------------------------------
  int i;
};
//*****************************************************************************
class C
  : virtual public B
{
public:
  //***************************************************************************
  // Constructors/Destructor
  //***************************************************************************
  //---------------------------------------------------------------------------
  // Name: C
  // Task: Constructor with the argument `a'
  //---------------------------------------------------------------------------
  explicit C(const int a);
  //---------------------------------------------------------------------------
  // Name: ~C
  // Task: Destructor
  //---------------------------------------------------------------------------
  virtual ~C();
};
//*****************************************************************************
class D
  : virtual public C
{
public:
  //***************************************************************************
  // Constructors/Destructor
  //***************************************************************************
  //---------------------------------------------------------------------------
  // Name: D
  // Task: Constructor with the argument `a'
  //---------------------------------------------------------------------------
  explicit D(const int a);
  //---------------------------------------------------------------------------
  // Name: ~D
  // Task: Destructor
  //---------------------------------------------------------------------------
  virtual ~D();
};
//*****************************************************************************
 //***************************************************************************
// Constructors/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
// Name: A
// Task: Constructor without argument
//---------------------------------------------------------------------------
A::A(void)
{
  cout<<this<<" constructor without argument of class
A"<<endl;
}
//---------------------------------------------------------------------------
// Name: ~A
// Task: Destructor
//---------------------------------------------------------------------------
A::~A()
{
  cout<<this<<" destructor of class A"<<endl;
}
//*****************************************************************************
//***************************************************************************
// Constructors/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
// Name: B
// Task: Constructor without argument
//---------------------------------------------------------------------------
B::B(void)
{
  cout<<this<<" constructor without argument of class
B"<<endl;
}
//---------------------------------------------------------------------------
// Name: B
// Task: Constructor with the argument `a'
//---------------------------------------------------------------------------
B::B(const int a)
{
  cout<<this<<" constructor of class B"<<endl;
  i=a;
}
//---------------------------------------------------------------------------
// Name: ~B
// Task: Destructor
//---------------------------------------------------------------------------
B::~B()
{
  cout<<this<<" destructor of class B"<<endl;
}
//*****************************************************************************
//***************************************************************************
// Constructors/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
// Name: C
// Task: Constructor with the argument `a'
//---------------------------------------------------------------------------
C::C(const int a)
  :B(a)
{
  cout<<this<<" constructor of class C"<<endl;
}
//---------------------------------------------------------------------------
// Name: ~C
// Task: Destructor
//---------------------------------------------------------------------------
C::~C()
{
  cout<<this<<" destructor of class C"<<endl;
}
//*****************************************************************************
//***************************************************************************
// Constructors/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
// Name: D
// Task: Constructor with the argument `a'
//---------------------------------------------------------------------------
D::D(const int a)
  :C(a)
{
  cout<<this<<" constructor of class D"<<endl;
}
//---------------------------------------------------------------------------
// Name: ~D
// Task: Destructor
//---------------------------------------------------------------------------
D::~D()
{
  cout<<this<<" destructor of class D"<<endl;
}
//*****************************************************************************
//---------------------------------------------------------------------------
// Name: main
// Task: Entry point
//---------------------------------------------------------------------------
int main(int argc,
         char *argv[])
{
  D d(10);
  cout<<"d constructed"<<endl;
  C c(10);
  cout<<"c constructed"<<endl;
  return 0;
}
-- 
François Bertel DIIC3-INC
bertel@ifsic.univ-rennes1.fr
fbertel@irisa.fr
 



More information about the Gcc-bugs mailing list