Overlapping java-like interfaces in C++

Miro Kropacek :

I've read on many places that Java's interface can be 100% emulated using C++'s abstract class with all pure virtual methods.

I'm trying to convert this piece of java code:

interface A {
    void a();
}

interface B extends A {
    void b();
}

class C implements A {
    public void a() {
    }
}

class D extends C implements B {
    public void b() {
    }
}

D d = new D();
d.a();
d.b();

into something like this in C++:

class A {
public:
    virtual void a() const = 0;
protected:
    virtual ~A() {
    }
};

class B : public A {
public:
    virtual void b() const = 0;
protected:
    virtual ~B() {
    }
};

class C : public /*implements*/ A {
public:
    virtual void a() const override {
    }
};

class D : public /*extends*/ C, public /*implements*/ B {
public:
    virtual void b() const override {
    }
};

D d;
d.a();
d.b();

but no matter how hard I try, I always end up with C++ complaining about ambiguity and/or missing body definitions.

The idea is that I want to derive from "C" which contains some shared code for all classes (here: "D" but there's more of them) and yet maintain the promise that "D" is 100% interchangeable with any class implementing "B" (incl. the parts from "A").

The errors I'm getting with C++ code above is:

../untitled1/main.cpp: In function ‘int main(int, char**)’:
../untitled1/main.cpp:39:7: error: cannot declare variable ‘d’ to be of abstract type ‘D’
     D d;
       ^
../untitled1/main.cpp:28:7: note:   because the following virtual functions are pure within ‘D’:
 class D : public /*extends*/ C, public /*implements*/ B {
       ^
../untitled1/main.cpp:7:18: note:   virtual void A::a() const
     virtual void a() const = 0;
                  ^
../untitled1/main.cpp:40:7: error: request for member ‘a’ is ambiguous
     d.a();
       ^
../untitled1/main.cpp:7:18: note: candidates are: virtual void A::a() const
     virtual void a() const = 0;
                  ^
../untitled1/main.cpp:23:18: note:                 virtual void C::a() const
     virtual void a() const override {
                  ^
StoryTeller - Unslander Monica :

This is a problem that is solved by virtual inheritance from A.

class A {
public:
    virtual void a() const = 0;
protected:
    virtual ~A() {
    }
};

class B : public virtual A {
public:
    virtual void b() const = 0;
protected:
    virtual ~B() {
    }
};

class C : public virtual A {
public:
    virtual void a() const override {
    }
};

class D : public C, public  B {
public:
    virtual void b() const override {
    }
};

The problem is that unless you specify that both C and B need to share an A sub-object (all derived classes contain their bases as sub-objects), the two sub-objects you get from inheriting both B and C will be unrelated.

In your original scheme, the implementation provided by C to the pure virtual member in A wasn't considered as an implementation for the same function required by the A in B.

Since now there is only one A sub-object, this problem goes away. But note that virtual inheritance is not without a price. So think if you really want to go with such a design.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=474115&siteId=1