Implementation of Interfaces with Inheritance in C++

192 views
Skip to first unread message

henning...@gmail.com

unread,
Sep 6, 2018, 4:10:50 PM9/6/18
to Cap'n Proto
Hi,
first of all, thanks to Kenton for all the great work and the new release candidate (which works for me, but I am just playing around currently so my coverage is below that of the various tests and that's why I didn't answer your request).

My question is regarding RPC interface implementation with inheritance in C++:

Given some legacy classes A and B like
class A {
    // some A features
};
class B : public A {
    // some B features on top of A
}

I'd like to make the A and B classes' features available via Capnproto RPC interfaces like

interface AA {
    aFunc @0 () -> (foo :Foo);
}

interface BB(AA) {
    bFunc @0 () -> (bar :Bar);
}

Implementation of the AA interface is straightforward like

class A : public AA::Server {
    // aFunc impl. for access of A's functionality
}

but when I now want to implement class B to inherit both from A (and thus indirectly from AA) and from BB::Server, I get a conflict on the ::Server classes' dispatch methods which I have no Idea how to resolve. 

class B : public A, public BB::Server {
    // bFunc impl. for access of B's additional functionality

This in turn also raises a related question: How to implement multiple RPC interfaces on one legacy class (say I want to have different capabilities for different operations of my class' data)? My original hope was that I can just inherit from all the interfaces. But since they are no "pure virtual" interfaces, again the dispatch methods will collide.

Still hoping I just didn't get it - thanks in advance for any advice!

Regards
Henning

Kenton Varda

unread,
Sep 6, 2018, 4:57:01 PM9/6/18
to henning...@gmail.com, Cap'n Proto
Hi Henning,

I'm not sure if there's a clean answer here. C++ multiple inheritance is extremely complicated in the details and tends to blow up like this.

At the very least, you will need to declare all your inheritance "virtual", like:

    class A: virtual public AA::Server { ... }
    class B: virtual public BB::Server { ... }

Then I think in class B you may need to explicitly specify that you want to inherit BB's implementation of `dispatchCall()`:

    class B: virtual public BB::Server {
    public:
      using BB::Server::dispatchCall;
    };

Unfortunately I'm not sure if that's enough to satisfy the compiler. You may find that you need to restructure things so that the RPC interfaces are implemented by separate adapter classes that wrap your normal C++ classes. You'd have wrappers like A_RpcAdapter (implements AA::Server, holds a reference to A) and B_RpcAdapter (implements BB::Server, holds a reference to B) -- but these wrapper types would not inherit each other.

In the case where you want a C++ class to inherit two Cap'n Proto interfaces, where neither capnp interface inherits the other already, you will need to declare a third Cap'n Proto interface that inherits both the others, and have your C++ class inherit from that. This is necessary in order to generate the correct `dispatchCall()` implementation that knows about both superclasses.

-Kenton

--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+unsubscribe@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.

Reply all
Reply to author
Forward
0 new messages