5

Suppose there is this interface:

class A{  
 public:  
  virtual foo()=0;  
};

And a class B which implements this interface:

class B:public A{    
 public:   
  virtual foo(){} //Foo implemented by B   
}

Finally, a class C which has classes A and B as base classes:

Class C : public A, public B {
};

My question is, there is a way to tell the compiler that the implementation for foo is the one from class B without doing an explicit call to B::foo()?

Daniel Saad
  • 909
  • 1
  • 7
  • 12
  • Why would you want to do it a different way? The only thing you'll get out of that is more confusion in your code. – TheAJ Dec 26 '12 at 17:57
  • I don't want to do a wrapper to all pure virtual functions derived from the interface. Instead i want to use the implementation from the concrete class. There is a way to do this without these wrappers, or i have to do on wrapper for each function to call the implementation from the concrete class? – Daniel Saad Dec 26 '12 at 17:59
  • 1
    Right now, `B` doesn't implement that interface. Did you intend `class B : public A` ? – Ben Voigt Dec 26 '12 at 18:03
  • 1
    Yes, i intended to. I edited the question =) Thank you – Daniel Saad Dec 26 '12 at 18:08
  • Your accepted answer is non-portable code which only works in g++, and only because of a compiler bug. You might want to rethink that. – Ben Voigt Dec 28 '12 at 14:40
  • @DanielSaad I encourage you to "unaccept" my incorrect answer :) – tmpearce Dec 28 '12 at 20:22

3 Answers3

3

As @BenVoigt pointed out in the comments, the below answer only works due to a bug in g++ (meaning it isn't guaranteed to keep working, and it definitely isn't portable). Thus, although it may do what you want if you use a particular (buggy) compiler, it isn't an option you should use.

Do use virtual inheritance though.


This isn't exactly the scenario that the code in the question implies, but the sentence

My question is, there is a way to tell the compiler that the implementation for foo is the one from class B without doing an explicit call to B::foo()?

seems to be asking for syntax to distinguish between multiple base versions of a function without using the :: qualifier.

You can do this with the using directive:

#include <iostream>
class A {
public:
A(){}
virtual void foo(){std::cout<<"A func";}
};

class B: virtual public A {
  public:
  B(){}
  virtual void foo(){std::cout<<"B func";}
};
class C:virtual public A, virtual public B {
    public:
    C(){}
    using A::foo; // tells the compiler which version to use
                   // could also say using B::foo, though this is unnecessary
};

int main() {
    C c;
    c.foo(); // prints "A func"
    return 0;
}

Of course, the code itself in the question doesn't require this at all, as the other answers have pointed out.

Community
  • 1
  • 1
tmpearce
  • 12,523
  • 4
  • 42
  • 60
  • This doesn't work without virtual inheritance, and isn't needed with virtual inheritance. – Ben Voigt Dec 28 '12 at 14:25
  • BTW, this is a g++ bug. It should print "B func" according to the Standard. – Ben Voigt Dec 28 '12 at 14:29
  • @BenVoigt Hah, thanks for pointing that out. I learned something there. I'd already +1'd your answer, so I can't do it again... I'll delete this answer in a bit to clean up the database and hopefully avoid confusing future searchers. – tmpearce Dec 28 '12 at 20:02
  • It might be more valuable to explain how tempting a `using` declaration is, and that it won't work according to the Standard, rather than deletion. – Ben Voigt Dec 28 '12 at 20:07
  • @BenVoigt Done. Feel free to edit any part of this answer if you feel further clarification is warranted. – tmpearce Dec 28 '12 at 20:19
2

Just use virtual inheritance, so that the A subobject provided by B is the same object used in C.

Or write class C : public B... it will be implicitly usable as an A anyway, via the base class B.


Before the question was edited:

B::foo is not compatible with A::foo.

The required signature is

ReturnType /* missing from question */ foo(A* const this /* this parameter is implicit */);

But B::foo has the signature

ReturnType foo(B* const this);

An A*, which will be passed to the virtual function, is not a B*, which the implementation requires. If B inherited from A, then the compiler would generate B::foo to accept an A* const subobject and find the B* const this object from that subobject pointer. But B::foo has no knowledge of the relationship in C.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
0

As you have the two base classes in your example (which might be a design issue/design smell, I'd review that) you have to explicitly call the implementation that you are after, be it A::foo() or B:foo().

If all B does is to provide the implementation of foo() I'd consider moving the implementation into A (you can provide an implementation for a pure virtual function) but even in this case you'd have to call it via its qualified name.

Timo Geusch
  • 24,095
  • 5
  • 52
  • 70