Virtual Inheritance - Missing Constructors

I have the following classes:

class Socket { Socket(); Socket( SOCKET s ); }; class Connection : public virtual Socket { Connection( IP ip ); }; 

These two classes contain some pure virtual functions and some non-virtual functions and some of their own data. Their essence is that I will get several types of sockets, implementing different protocols.

Therefore, I specialize in these two classes:

 class ProtocolSocket : public virtual Socket { ProtocolSocket() {} ProtocolSocket( SOCKET s ) : Socket( s ) { ; } }; class ProtocolConnection : public ProtocolSocket, public virtual Connection { ProtocolConnection( SOCKET s, IP ip ) : ProtocolSocket( s ), Connection( ip ) {;} }; 

Something went wrong - as I am sure, many of you see. I am trying to create a ProtocolConnection:

 new ProtocolConnection( s, ip ); 

Construction continues as follows:

 start ctor ProtocolConnection start ctor Connection start ctor Socket Socket(); - default ctor via Connection init list end ctor Socket Connection(); - default ctor ProtocolConnection init list end ctor Connection start ctor ProtocolSocket start ctor Socket // Socket( s ); - skipped!!! - would have been from init // list of ProtocolSocket, but ctor for this object // already called! end ctor Socket ProtocolSocket( s ); -from init list of ProtocolConnection() end ctor ProtocolSocket ProtocolConnection( s, ip ); end ctor ProtocolConnection 

Skipping this second Socket constructor is what the language specification says, and for good reason.

How to make it invoke a constructor named Socket (s), not an earlier one?

I intend to have several derived classes, for example. Also, OtherProtocolSocket and OtherProcolConnection, at the same level as the ProtocoSocket and ProtocolConnection objects.

The effect that I am trying to achieve, I want to build the ProtocolSocket and ProtocolConnection objects, and then transfer them around my system as Socket and Connection objects. Therefore, after I created the socket, it implements this protocol, I just read and write it without worrying about the details of the underlying protocol.

Connection objects must inherit all methods from socket objects.

@UPDATE:

DyP suggests adding an initializer for Socket in ProtocolConnection. This solves the problem. I would give you consent to this ... but it was just in the comment.

+1
c ++
Jun 05 '13 at 16:43
source share
2 answers

The key to remembering is that the constructors for virtual base classes are executed as part of the initialization of the derived class itself (even before the creation of other base classes). Thus, the slide of your construction order is incorrect.

In fact, what happens when you build the ProtocolConnection is that it first creates a Socket, then Connection (since you practically inherited it), and finally ProtcolSocket.

To call the constructor of the socket you want, you must call its constructor as part of the initializer list of the ProtocolSocket element, since

 class ProtocolConnection: public ProtocolSocket, public virtual Connection { public: ProtocolConnection(int s, int ip) : Socket(s), Connection(ip), ProtocolSocket(s) // Note, also reordered, since all virtual bases are initialized before the // non-virtual bases { std::cout << __PRETTY_FUNCTION__ << std::endl; } }; 

Finally, as a note, I would recommend simplifying your inheritance hierarchy. In particular, virtual inheritance and the use of multiple constructors complicate factors.

+3
Jun 05 '13 at 17:01
source share
β€” -

DAG Inheritance:

  ProtocolConnection / \ non-virtual virtual / \ ProtocolSocket Connection | | virtual virtual | | Socket Socket 

Note that there is only one Socket subobject in an object of type ProtocolConnection due to virtual inheritance.

[class.base.init] / 10

First, and only for the constructor of the derived class (1.8) itself, the virtual base classes are initialized in the order in which they appear at the first intersection from left to right left to right of the directed acyclic graph of the base classes, where β€œfrom left to right” is the order in which the base classes appear classes in the base specifier-list of the derived class.

Initialization of virtual base classes is carried out using a through transition from left to right in depth. Workaround:

  (0) ProtocolConnection / \ nv v / \ (1) ProtocolSocket (3) Connection | | v nv | | (2) Socket (4) Socket 

Leads to the initialization order:

(2); (3); (one); (0)
Socket Connection ProtocolSocket (not a virtual base class); ProtocolConnection

The most derived ProtocolConnection class should include initializers for all virtual base classes. If the virtual base class does not appear in the mem-initializer list of the derived class itself, the subobject of this virtual base class will be built by default.

+2
Jun 05 '13 at 17:15
source share



All Articles