Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multiple inheritance without virtual inheritance

I am trying to understand multiple inheritance, here is my code:

struct A {
  A() {}
  static int n;
  static int increment() { return ++n; }
};
int A::n = 0;

struct B : public A {};
struct C : public A {};
struct D : public B, C {};

int main() {
  D d;
  cout<<d.increment()<<endl;
  cout<<d.increment()<<endl;
}

This code works. However, if I change increment() to non-static it will fail.

My questions:

  1. Why compiler complains ambiguous call of non-static version of increment(), while satisfies with the static one?
  2. If I add another increment() function to B or C, compiler will complain too, even declared as static. Why?
like image 297
Deqing Avatar asked Aug 19 '14 06:08

Deqing


3 Answers

What does ambiguous mean?

A compiler complains of ambiguous calls when it cannot decide which function to call given the context. So, in order to understand the complaints, you have to check what the possible ambiguities could be.

Why compiler complains ambiguous call of non-static version of increment(), while satisfies with the static one?

By definition, a static function of a class does not depend on any instance of the class. This is emphasized by the fact that you could call it A::increment() (see, no instance).

The problem of the diamond inheritance is not that the compiler does not know which code to execute, it's that is does not know which this to provide (there are two A in your D object, one contained in B and one in C).

When you use a static function of A, no implicit this is passed, so there is no issue; if you try to use a non-static function, then the compiler cannot decide whether this should point to the A in B or in C, it's ambiguous.

If I add another increment() function to B or C, compiler will complain too, even declared as static. Why?

At this point, the compiler may choose between B::increment() and C::increment(), which should it pick? It's ambiguous.

When you have a linear hierarchy, it calls the "closest" to it (which hides those further down the inheritance tree), but here B and C are two independent branches and there is no "better" branch.

Note: even if B does not implement increment, since A does you can call B::increment() which actually calls A::increment(). The same goes for C.

like image 151
Matthieu M. Avatar answered Oct 05 '22 23:10

Matthieu M.


  1. It is called diamond inheritance problem. You have two classes, that are derived from A. Then class derived from two. You have two versions of non-static void increment(). With static you have one.
  2. Because you can, but should never override non virtual function, and maybe your compiler is strict one or in strict mode.

Diamond inheritance: http://www.parashift.com/c++-faq/mi-diamond.html Hiding functions: http://www.parashift.com/c++-faq/hiding-inherited-public.html

like image 34
DoctorMoisha Avatar answered Oct 06 '22 00:10

DoctorMoisha


This statement:

struct D : public B, C {};

Would create two instances of A. Compiler needs to know from which instance you intend to call the method. A static function is nothing but a global function, which is friend to the class - the only requirement is fully-qualified name when caller intents to call it. Static won't play any role in inheritance.

like image 39
Ajay Avatar answered Oct 06 '22 00:10

Ajay