2

We have 4 classes.

  • Field
  • ForbiddenField inherits from Field
  • RequiredField inherits from Field
  • ForbiquiredField : the subject of my question

I would like to define a function Validate()in ForbiquiredField, originaly defined in ForbiddenField and RequiredField.
I would like to use both of functions X() defined in ForbiddenField and RequiredField.
Is it a good deal to define:

ForbiquiredField inherits ForbiddenField, RequiredField
{
    Validate()
    {
        ForbiddenField.Validate();
        RequiredField.Validate();
        /// Some specific tasks
    }
}

Or is there a better way to proceed?

  • 3
    What language are you using? Quite a few popular languages don't support multiple inheritance. – Bart van Ingen Schenau Jun 27 '18 at 13:47
  • Arguments about Downvotes are Welcome. – Freddykong Jun 27 '18 at 13:53
  • Possible duplicate from Stackoverflow: stackoverflow.com/questions/2456154/… – Freddykong Jun 27 '18 at 13:54
  • 1
    @BartvanIngenSchenau I don't think it would provide any clarification but ok : It's Webdev22 – Freddykong Jun 27 '18 at 13:55
  • 1
    Instead of saying ClassB and ClassC, use the actual names from your problem domain, like Player and Weapon, or Customer and Product. – Robert Harvey Jun 27 '18 at 14:25
5

This is related to the Diamond Problem. Either the language that offers multiple inheritance has explicit support to avoid the related problems, or your best bet is to avoid (multiple) inheritance.

Let me recapitulate the problem in pseudocode:

class ClassA { X() { ... } }
class ClassB extends ClassA { X() { ClassA.X(); ... } }
class ClassC extends ClassA { X() { ClassA.X(); ... } }
class ClassD extends ClassB, ClassC {
  X() { ClassB.X(); ClassC.X(); ... }
}

In this design where ClassB and ClassC also call their super method in ClassA, a call to ClassD.X() will end up calling ClassA.X() twice. This is the depth-first resolution approach to multiple inheritance as used in C++ and may or may not be what you want.

Other languages try to order (“linearize”) the base classes so that we can simply call the next base class, without knowing in advance which class that will be. Python is one such language:

class ClassA(object):
  def x(self):
     ...

class ClassB(ClassA):
  def x(self):
    super().x(); ...

class ClassC(ClassA):
  def x(self):
    super().x(); ...

class ClassD(ClassB, ClassC):
  def x(self):
    super().x(); ...

For ClassD, the C3 method resolution order (MRO) algorithm will order the classes as ClassD, ClassB, ClassC, ClassA and searches the classes for methods left-to-right. The super().x() call does not call into the base class, but continues the search in the MRO for that object. So in this case, the super-call from the ClassB.x() method will actually be resolved to ClassC.x(). There are limitations to this approach:

  • This requires explicit support from the language's object model. It is not a feature that can be retro-fit later.
  • The resulting MRO can be unintuitive, because it doesn't necessarily dispatch to the base class, but could dispatch to seemingly unrelated classes.
  • All classes in a multiple inheritance hierarchy must cooperate. Everyone must forward the super().x() calls correctly, or this will break. If different classes require different arguments, passing the arguments can be tricky (this is frequently an issue with Python's __init__() method that serves as a constructor).

Because of these problems, very few languages support real multiple inheritance (most notably Python, C++, and Perl). Even in these languages, multiple inheritance is generally discouraged. Other languages use traits or mixins to provide some aspects of multiple inheritance, without having to define a complicated method resolution order.

In a scenario where you want to dynamically add functionality to some object, the decorator pattern could be more appropriate. It only needs interface inheritance, and completely avoids the problems of class inheritance.

  1. Define an interface like interface CanDoX { X(); }
  2. Provide a base implementation, e.g. class ClassA implements CanDoX { ... }
  3. Implement various decorators that implement CanDoX and take a CanDoX instance in their constructor:

    class DecorateXWithB implements CanDoX {
      private CanDoX base;
      X() { base.X(); ... }
    }
    
  4. You can now assemble a pipeline of decorators in exactly the order you want:

    new DecorateXWithD(
        new DecorateXWithC(
            new DecorateXWithB(
                new ClassA(...))))
    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.