lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi] Why is this taxonomy not a DAG?


From: Greg Chicares
Subject: [lmi] Why is this taxonomy not a DAG?
Date: Mon, 11 Feb 2019 15:12:20 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.4.0

I need to implement a set of products with an "inheritance" graph
like this (suspend any disbelief that we descend from fish):

          +Mermaid+
          |       |
       +Human+    Gills
       |     |
     +Fish+  Lungs
     |    |
  Animal  Gills

where all classes would have a common "zoological entity" base class.

I was hoping to use C++ inheritance to do that, with "gills" and "lungs"
being mixin classes, such that a declaration like
  class Mermaid : public Human : public Gills // add "virtual" as needed
would suppress Lungs and provide Gills. Yet, even though C++17 (N4659)
at 15.6.2/13.1 prescribes a
  "depth-first left-to-right traversal of the graph of base classes"
and the tree above is a graph, apparently a DAG is specifically meant,
as the traversal order is not
  Animal, Gills, Fish, Lungs, Human, Mermaid, Gills (again)
but rather
  Animal, Gills, Fish, Lungs, Human, Mermaid
and the right-hand "Gills" mixin is pruned before traversal.

Is this because the graph is not directed, or because it's not acyclic?
That's the only question I'm stuck on.

I can see many ways to get the desired result. I was just hoping that
C++'s multiple inheritance would work because it affords such a compact,
readable framework for expressing the graph. Alas, in this case, the
lungs-or-gills property can't be overridden by adding the appropriate
mixin to the most-derived class (when that same mixin appears earlier).

In the unlikely event that a concrete test case is wanted, I append the
one I wrote to explore this issue; it may be used thus:

  /opt/lmi/src/lmi[0]$make unit_tests unit_test_targets=sandbox_test.exe 2>&1 
|less -S

---------8<--------8<--------8<--------8<--------8<--------8<--------8<-------
diff --git a/sandbox_test.cpp b/sandbox_test.cpp
index bbc998e0..adcb002a 100644
--- a/sandbox_test.cpp
+++ b/sandbox_test.cpp
@@ -23,7 +23,50 @@
 
 #include "test_tools.hpp"
 
+class B
+{
+  public:
+    B() {}
+    void set(int i) {i_ = i;}
+    int i() {return i_;}
+    void hello(char const* c) {std::cout << c << std::endl;}
+  private:
+    int i_ {};
+};
+
+// base for a particular family of derived classes
+class C : virtual public B { public: C(){set(3); hello(__FUNCTION__);} };
+
+// mixins
+class M0: virtual public B {public: M0(){set(5); hello(__FUNCTION__);} };
+class M1: virtual public B {public: M1(){set(7); hello(__FUNCTION__);} };
+
+class D0: virtual public C, virtual public M0 {public: D0(){ 
hello(__FUNCTION__);} };
+class D1: public C, public M1 {public: D1(){ hello(__FUNCTION__);} };
+
+class DX: virtual public D0, virtual public M1 {public: DX(){ 
hello(__FUNCTION__);} };
+class DY: virtual public DX, virtual public M0 {public: DY(){ 
hello(__FUNCTION__);} };
+
+// C++17 (N4659) [15.6.2/13.1]:
+// "depth-first left-to-right traversal of the graph of base classes"
+//
+//          +---DY---+
+//          |        |
+//       +--DX--+   M0
+//       |      |
+//     +-D0-+  M1
+//     |    |
+//     C   M0
+//
+// actual order is C M0 D0 M1 DX DY
+// M0 on the right-hand branch is pruned as a duplicate
+
 int test_main(int, char*[])
 {
+    std::cout << "D0().i() " << D0().i() << std::endl;
+    std::cout << "D1().i() " << D1().i() << std::endl;
+    std::cout << "DX().i() " << DX().i() << std::endl;
+    std::cout << "DY().i() " << DY().i() << std::endl;
+
     return 0;
 }
--------->8-------->8-------->8-------->8-------->8-------->8-------->8-------



reply via email to

[Prev in Thread] Current Thread [Next in Thread]