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 {
^
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.