1

I have this, maybe a little bit complex class hierarchy:

class BS {
  public:
    virtual void meth()=0;
};

class BCA : public virtual BS {
};

class BSS : public virtual BS {
};

class BCS : public virtual BCA, public virtual BSS {
};

class BI4 {
  public:
    void meth() {};
};

class BT4 : public virtual BI4, public virtual BSS {
};

class T4 : public virtual BCS, public virtual BT4 {
};

int main() {
  T4 t4;
};

Now the problem is that although the void meth() is available in the inheritance graph, despite this code won't compile:

$ g++ -c t.cc -std=c++11
t.cc: In function ‘int main()’:
t.cc:27:6: error: cannot declare variable ‘t4’ to be of abstract type ‘T4’
   T4 t4;
      ^
t.cc:23:7: note:   because the following virtual functions are pure within ‘T4’:
 class T4 : public virtual BCS, public virtual BT4 {
       ^
t.cc:3:18: note:        virtual void BS::meth()
     virtual void meth()=0;
                  ^
t.cc:3:18: note:        virtual void BS::meth()

It seems to me as if BS somehow wouldn't see the overloaded meth() method through the BS->BCA->BCS->T4->BT4->BI4 chain.
But why? The method is clearly available, the C3 linearization algorithm used by the C++ should be able very clearly find it.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
peterh
  • 11,875
  • 18
  • 85
  • 108
  • Nitpick: you mean "overridden" not "overloaded". – Thomas Jul 06 '16 at 18:30
  • 1
    The multiple `virtual` inheritance relationships are a bit of overkill. You only need that for base class sub-objects that would otherwise occur two or more times. – Cheers and hth. - Alf Jul 06 '16 at 18:35
  • "little bit complex" o.O It wouldn't be quite so bad maybe if the names were in any way sensible. – Lightness Races in Orbit Jul 06 '16 at 18:41
  • 1
    _"the BS->BCA->BCS->T4->BT4->BI4 chain"_ goes up then comes down; that's not how it works! – Lightness Races in Orbit Jul 06 '16 at 18:42
  • While you can't do this, you can still delegate to BI4 (even to T in a template). – lorro Jul 06 '16 at 18:45
  • @LightnessRacesinOrbit Other C3 linearization languages/frameworks do this seamlessly, f.e. see the [dojo](https://dojotoolkit.org) Javascript framework. – peterh Jul 06 '16 at 19:33
  • @LightnessRacesinOrbit Uhm, sorry. I wanted to give a sanitized example, the pure logical problem, without the implementation details (you can check the whole code [here](https://github.com/HorvathAkosPeter/pipenet/tree/master/posxx)). – peterh Jul 06 '16 at 19:35
  • @Cheersandhth.-Alf Agreed, I've made a class hierarchy graph with doxygen and minimized the virtual inheritances to the diamonds. – peterh Jul 06 '16 at 19:42

3 Answers3

5

The rules of the language don't allow it. A virtual function can only be overridden by the declaration of a function with the same name and parameters in a derived class. Since BI4 isn't derived from BS, BI4::meth cannot override BS::meth. If a class inherits (directly or indirectly) from both BS and BI4, then it inherits two functions called meth: one from BS, still abstract and not overridden, and one from BI4.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
2

BI4 does not inherit from BS either directly or indirectly, so its method BI4::meth() is entirely unrelated and cannot override BS::meth().

You can only override methods from base classes, not from "sibling" or "uncle" classes.

Thomas
  • 174,939
  • 50
  • 355
  • 478
2

There are two main aspects:

  • A given class can only override member functions from its base classes.
    Since your BI4 class doesn't have BS as a base class, it can't override anything from BS.
  • It's possible to inherit in an implementation of a pure virtual function defined in a virtual base class, much like in Java, but the class providing that implementation must itself also have that virtual base class.

Example:

struct Base
{
    virtual void foo() = 0;
};

#ifdef GOOD
    struct Impl_foo: virtual Base
    {
        void foo() override {}
    };
#else
    struct Impl_foo
    {
        virtual void foo() {}
    };
#endif

struct Abstract_derived: virtual Base
{};

struct Derived
    : Abstract_derived
    , Impl_foo      // Java-like implementation inheritance.
                    // In C++ called "by dominance".
{};

auto main()
    -> int
{
    Derived o;
    o.foo();
}

Without defining the GOOD macro symbol, this code doesn't compile.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331