Multiple inheritance

#include<iostream>
using namespace std;

class A

{
   int a;
   int b;
   public:
   void eat()
   {
      cout<<"A::eat()"<<endl;
   }
};

class B: public A
{
   public:
   void eat()
   {

      cout<<"B::eat()"<<endl;

   }

};

class C: public A
{

   public:
   void eat()

   {

      cout<<"C::eat()"<<endl;

   }

};

class D: public B, C
{

};

int foo(A *ptr)
{

ptr->eat();

}
main()
{

D obj;
foo(&(obj.B)); //error. How do i call with D B part.

}

      

The above call to foo is a compile-time error. I want to call foo with the obj B part without using virtual inheritance. How should I do it.

Also, in the case of virtual inheritance, why should the offset information be stored in the vtable. This can be determined at compile time. In the above case, if we pass foo with an object D, at compile time we can calculate the offset of the D part A.

0


source to share


4 answers


Inheriting twice

With double inheritance, you have an ambiguity - the compiler cannot know which of the two databases you want to use. If you want to have two bases A (sometimes you can do that), you can choose between them by casting in B or C. The most suitable defaults are static_cast

(as the weakest), however it is not needed (it is even stronger than your case) since you are not doing a derived type. The custom template safe_cast

should do the job:

/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}

main()
{

  D obj;
  foo(safe_cast<B *>(&obj)); //error. How do i call with D B part.

}

      

Compile-time types - use templates

Also, in the case of virtual inheritance, why should the estimate information be stored in the vtable. It can be determined at compile time. In the above case, if we pass foo with D, at compile time we can only calculate the offset of the DA part.

It's a delusion. The foo function, as written, now has no compilation information for type ptr other than A *, even if you pass in B * or C *. If you want foo to be able to act based on a passed compile-time type, you need to use templates:

template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
  ptr->eat();
}

      

Virtual inheritance



Your questions mentions virtual inheritance. If you want to use virtual inheritance, you need to specify it like this:

class B: public virtual A ...

class C: public virtual A ...

      

With this the code will compile, but with this solution, you cannot choose between B :: A or C :: A (there is only one A), so this is probably not what you are talking about.

Virtual functions

Also, your questions seem to confuse two different concepts, virtual inheritance (which means sharing the same base class between two intermediate base classes) and virtual functions (which means calling a function of a derived class is called using a base class pointer). If you want B :: eat to be called using a pointer A, you can do it without virtual inheritance (in fact, virtual inheritance will prevent you, as described above) using virtual functions:

class A
{
   int a;
   int b;

   public:
   virtual void eat()
   {
      cout<<"A::eat()"<<endl;
   }
};

      

If virtual functions are not acceptable to you, the compile time mechanism for doing this is templates, as described above.

+6


source


Use casting - static_cast

required here to release hierarchy.



main()
{
  D obj;
  foo(static_cast<B*>(&obj));
}

      

+3


source


First of all, it obj

does not have a member named B. It inherits from B, which means that it inherits all members of B as its own.

You may call:

foo(static_cast<B*>(&obj));
      

to make it work.
+1


source


I don't think static_cast will work.

When you are in the foo function, all compilers know that you have a pointer to A, no matter what type you passed as a parameter.

Unless you are using virtual inheritance, I think there is no way to call function B from a pointer to A.

+1


source







All Articles