1

It looks like that there is something that I don't understand about multiple inheritance and abstract methods. I am implementing some hardware functionality in SystemC, with multiple target HWs. I have two different levels of software implementation. The first one is optimized for performance; the second one on its top, has some display, etc. functionality. [Note, in the hardware world "top" refers to the highest level instance which is usually a wrapper or a testbench for the hardware instance]

To actually handle a HW, in scSW I implemented "Hold()". When I want to use it in the higher level (see SW and SW2), my compiler said

error: ‘scHW’ is an ambiguous base of ‘SW’
 struct SW : scSW, HW { virtual bool Holds(){return scHW::Holds();} };

and

invalid new-expression of abstract class type ‘SW2’
     SW2* S2 = new SW2;
                   ^~~
because the following virtual functions are pure within ‘SW2’:
 struct SW2 : scSW, HW {  };

It also added:

 request for member ‘Holds’ is ambiguous
     std::cerr << S2->Holds();

I especially do not see, how can a method be pure and ambiguous, at the same time? What do I wrong and what is the correct way of coding what I want?

#include <iostream>
struct Virtual { virtual bool Holds() = 0;};
struct scHW { bool Holds(){return true;}};
struct scSW : scHW, Virtual {};
struct HW : scHW { };
struct HW2 : scHW { virtual bool Holds(){return scHW::Holds();}};
struct SW : scSW, HW { virtual bool Holds(){return scHW::Holds();} };
struct SW2 : scSW, HW {  };

int main()
{
    HW* H = new HW;
    HW2* H2 = new HW2;
    scHW* H1 = new scHW;
    SW* S = new SW;
    SW2* S2 = new SW2;
    std::cerr << S->Holds();
    std::cerr << H->Holds();
    std::cerr << H2->Holds();
    std::cerr << S2->Holds();
}
Paul Floyd
  • 5,530
  • 5
  • 29
  • 43
katang
  • 2,474
  • 5
  • 24
  • 48

2 Answers2

1

It's pure and ambiguous at the same time because name lookup and virtual function overriding are mostly orthogonal mechanisms. You see here:

struct scSW : scHW, Virtual {};
struct HW : scHW { };

Looking up Holds in scSW will go into two different base class sub-object (as explained on your previous question). The scHW and Virtual bases. As such, the lookup is ambiguous. Those are two different functions in two different classes that are referred to by the same identifier.

Which not quite so coincidentally is also why Virtual::Holds is not overridden in scSW. The member from scHW is unrelated. There is no virtual function overrider in scSW, so that class remains abstract.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
0

Looks like you might not want multiple inheritance, and just do:

 struct scHW : Virtual { virtual bool Holds(){return true;}};
 struct scSW : scHW {};
 ...

that way scHW isn't abstract and can be instantiated.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • I definitely want multiple inheritance: Virtual provides the abstract handling, and scSW the physical one. The abstract function enables other methods of scSW to implement handling a concrete HW without knowing the details of the hardware, in this case different hardware units. In the way you proposed, Virtual provides a 'default' method, and the programmer of the hardware driver is not forced to implement (override) the method. – katang Feb 04 '19 at 12:25