Python
Some useful resources to accompany this example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
import abc class AbstractEntity(object): __metaclass__ = abc.ABCMeta @classmethod def get_inherent_properties(cls): return [] @abc.abstractmethod def get_properties(self): pass class Entity(AbstractEntity): is_alive = False inherent_properties = ['exists'] def __init__(self,individual_properties): self.individual_properties = individual_properties @classmethod def get_inherent_properties(cls): # This feels like a hack, but it's the only good way to get something from all immediate parent classes - circumvents MRO. return cls.inherent_properties + sum(map(lambda x: x.get_inherent_properties(), cls.__bases__),[]) def get_properties(self): return self.__class__.get_inherent_properties() + self.individual_properties class SentientEntity(Entity): is_alive = True inherent_properties = ['alive', 'feels'] def __init__(self,individual_properties): self.individual_properties = individual_properties class Robot(Entity): is_alive = False inherent_properties = ['electric'] def __init__(self,individual_properties): self.individual_properties = individual_properties class Human(SentientEntity): inherent_properties = ['organic', 'bipedal'] def __init__(self,individual_properties): self.individual_properties = individual_properties # Inheriting from Robot first will cause sentient robots and cyborgs to *not* be alive. class SentientRobot(SentientEntity,Robot): def __init__(self,individual_properties): self.individual_properties = individual_properties class Cyborg(SentientRobot,Human): def __init__(self,individual_properties): self.individual_properties = individual_properties def main(): print SentientEntity.is_alive print Human.is_alive print Robot.is_alive print SentientRobot.is_alive print Cyborg.is_alive print SentientRobot.__mro__ print Cyborg.__mro__ print Human(['computer scientist']).get_properties() # Ugh! We get copies of several items! print SentientRobot(['wheels']).get_properties() print Cyborg(['metal torso']).get_properties() # Could wrap in list(set(...)) to fix. We've circumvented the MRO system. if __name__ == "__main__": main() |
Output:
1 2 3 4 5 6 7 8 9 10 |
True True False True True (<class '__main__.SentientRobot'>, <class '__main__.SentientEntity'>, <class '__main__.Robot'>, <class '__main__.Entity'>, <class '__main__.AbstractEntity'>, <type 'object'>) (<class '__main__.Cyborg'>, <class '__main__.SentientRobot'>, <class '__main__.Human'>, <class '__main__.SentientEntity'>, <class '__main__.Robot'>, <class '__main__.Entity'>, <class '__main__.AbstractEntity'>, <type 'object'>) ['organic', 'bipedal', 'alive', 'feels', 'exists', 'computer scientist'] ['alive', 'feels', 'alive', 'feels', 'exists', 'electric', 'exists', 'wheels'] ['organic', 'bipedal', 'alive', 'feels', 'alive', 'feels', 'exists', 'electric', 'exists', 'organic', 'bipedal', 'alive', 'feels', 'exists', 'metal torso'] |
C++
To accompany this example, you may wish to read:
- Solving the Diamond Problem with Virtual Inheritance by Andrei Milea
- Derived classes at cppreference.com
C++ doesn’t, by default, use a resolution order to resolve the diamond problem.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include<iostream> using namespace std; class A { public: A() { cout << "A's constructor called" << endl; } }; class B: public A { public: B() { cout << "B's constructor called" << endl; } }; class C: public A { public: C() { cout << "C's constructor called" << endl; } }; class D: public B, public C { public: D() { cout << "D's constructor called" << endl; } }; int main() { D d; return 0; } |
Output:
1 2 3 4 5 |
A's constructor called B's constructor called A's constructor called C's constructor called D's constructor called |
This makes referring to inherited methods from A in D problematic, as it is ambiguous. Assume A has a method write()
, calling write from D will result in an error – do you mean A::B::D
‘s write()
, or do you mean A::C::D
‘s write()
?
Solution: Make B and C inherit from virtual public A
. We are then guaranteed to get only a single instance of the common base class.Then, the output is:
1 2 3 4 |
A's constructor called B's constructor called C's constructor called D's constructor called |