8

Conside the following sample code below:

#include <iostream>

using namespace std;

class base
{
   public:
      base()
      {
         cout << "ctor in base class\n";
      }
};

class derived1 : public base
{
   public:
      derived1()
      {
         cout <<"ctor in derived1 class\n";
      }
};

class derived2 : public derived1
{
   public:
      derived2() : base()
      {
         cout << "ctor in derived2 class\n";
      }
};

int main()
{
   derived2 d2obj;
   return 0;
}

This gives the error:

error: type `base' is not a direct base of `derived2'

Why is this error occurring? If i make the base class virtual, the error is no longer there. What is the reason for this?

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
nitin_cherian
  • 6,405
  • 21
  • 76
  • 127

3 Answers3

14

Because base is not a direct base of derived2. You have to give a constructor for your direct bases, derived1 in this case.

Virtual bases are the exception. They are always initialized in leaf classes, otherwise potentially you get multiple constructor calls for the same base. So if you make base virtual, not only can you initialize it in derived2, you must.

The issue arises when you have a derivation graph that is not a tree. IBM has a pretty picture. If you don't make the base (V in the example) virtual (everywhere) you'll have multiple copies. If you do make it virtual everywhere, you'll only have one copy, but then the direct children can not run the constructor (it would run > 1 time) and the leaf class must. For more details, best to search the web.

smparkes
  • 13,807
  • 4
  • 36
  • 61
  • Thanks smparkes. I was expecting this answer. But could you explain a little more on the `Virtual bases are the exception` – nitin_cherian Dec 07 '11 at 17:00
  • Hard, in 600 characters, I'm afraid. The issue arises when you have a derivation graph that is not a tree. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v7v91/index.jsp?topic=%2Fcom.ibm.vacpp7l.doc%2Flanguage%2Fref%2Fclrc14cplr135.htm has a pretty picture. If you don't make the base (V in the example) virtual (everywhere) you'll have multiple copies. If you do make it virtual everywhere, you'll only have one copy, but then the direct children can not run the constructor (it would run > 1 time) and the leaf class must. For more details, best to search the web. – smparkes Dec 07 '11 at 17:08
  • 1
    @smparkes: Instead of expanding the answer in a 600 character limit comment, maybe you should just expand the answer? :D – Mooing Duck Dec 07 '11 at 17:39
  • 1
    @MooingDuck, thanks. Guess I was wimping out. Virtual bases are such a tar baby, I think I (subconsciously) wanted the 600 character limit. – smparkes Dec 07 '11 at 17:54
6

Change

class derived2 : public derived1
{
   public:
      derived2() : base()
      {
         cout << "ctor in derived2 class\n";
      }
};

to

class derived2 : public derived1
{
   public:
      derived2() : derived1()
      {
         cout << "ctor in derived2 class\n";
      }
};

This is because you trying to call base1 constructor from a grand child derived2.

If you change the derivation of derived1 from base1 to be virtual. It is ok to call base1 from derived2. More details here.

parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85
0

You have derived1 in between. You can only call immediate parents within the initializer list

danca
  • 509
  • 4
  • 11