I am writing a “filesystem” abstraction in C++, with the following inheritance hierarchy:
[Node]
^
|
+----[Dir]
|
+----[File]
Where Node defines all the behavior identical to both (Name, time last modified, etc.) however, I have a Node method called getParent() that returns a type Dir *. This works fine, because although Dir.h obviously needs to know the implementation specification in Node.h, Node.h doesn’t need to know about what’s in Dir.h so I can use a forward declaration. Great.
However, I recently decided to add in multiple inheritance so I can support “snapshots” of the filesystem at a certain time. These are read-only versions of the “live” Node File and Dir classes, and since the live versions can be read from as well as written to, I have each live version inherit from its snapshot dual:
[NodeSnapshot] <------ [Node]
^ ^
| |
+---[DirSnapshot]<---+---[Dir]
| |
+---[FileSnapshot]<--+---[File]
Therefore, Dir inherits from both Node and DirSnapshot, and File inherits from both FileSnapshot and Node. Everything looks good to be so far, until we get to the declaration of getParent(). In NodeSnapshot, I return a DirSnapshot *. No problem, I can use a forward declaration again. However, in Node, I want to return Dir *. I, as a programmer, know that Dir is a subtype of DirSnapshot, however the compiler has no way of knowing this because a forward declaration doesn’t have any of this useful information embedded in it.
Is it possible to inform the compiler that this forward declaration is a subclass and therefore it shouldn’t tell me that the return type of Dir::getParent() does not covary with that of DirSnapshot::getParent()?
It is possible to implement/emulate return type covariance without any language support, though solutions tend to be verbose. On the other hand, mutually recursive definitions are no problem. One needs to use non-virtual public (inline) functions that call virtual private functions. It is a useful technique, some even argue that all interfaces should be implemented like this.
Here’s an example: