Multiple Inheritance / Implementation alternative

Assuming Multiple Inheritance was supported in C#, I would have the following classes.

class BaseClass : MonoBehaviour
{
     // Common functionality
}

class SubClassA : BaseClass
{
     // Unique functionality & implementation
}

class SubClassB : BaseClass, MaskableGraphic
{
     // Unique functionality & implementation
}

Given that Multiple Inheritance is not supported, I need to have the BaseClass inherit from MaskableGraphic which comes with extra luggage which isn’t needs by the SubClassA and more importantly adds extra components via [RequireComponent].

Any suggestions on how to implement this?

1 Like

How about an interface?

1 Like

In C#, like Java, you use interfaces.

public interface IBaseType
{

    string SomeProperty { get; set; }

    void Foo();

}

public class SubTypeA : MonoBehaviour, IBaseType
{

    private string _value;
  
    public string SomeProperty
    {
        get { return _value; }
        set { _value = value; }
    }
  
    public void Foo()
    {
        Debug.Log("DID FOO!");
    }

}

public class SubTypeB : MaskableGraphic, IBaseType
{

    private string _value;
  
    public string SomeProperty
    {
        get { return _value; }
        set { _value = value; }
    }
  
    public void Foo()
    {
        Debug.Log("DID FOO!");
    }

}

Thing is interfaces don’t allow for generalized implementation though, it only accepts interface definitions.

What you can do is create consumable composite objects for the interface type if you need generalized implementation.

public interface IBaseType
{

    string SomeProperty { get; set; }

    void Foo();

}

public class ConsumableBaseType : IBaseType
{

    private string _value;
  
    public string SomeProperty
    {
        get { return _value; }
        set { _value = value; }
    }
  
    public void Foo()
    {
        Debug.Log("DID FOO!");
    }
  
}

public class SubTypeA : MonoBehaviour, IBaseType
{

    private ConsumableBaseType _composite = new ComsumableBaseType();
  
    public string SomeProperty
    {
        get { return _composite.SomeProperty; }
        set { _composite.SomeProperty = value; }
    }
  
    public void Foo()
    {
        _composite.Foo();
    }

}

public class SubTypeB : MaskableGraphic, IBaseType
{

    private ConsumableBaseType _composite = new ComsumableBaseType();
  
    public string SomeProperty
    {
        get { return _composite.SomeProperty; }
        set { _composite.SomeProperty = value; }
    }
  
    public void Foo()
    {
        _composite.Foo();
    }

}

If the consumable needs a reference to the concrete object that consumed it… just pass in a reference as ‘IBaseType’ in its constructor:

public class ConsumableBaseType : IBaseType
{

    private IBaseType _owner;
    private string _value;
  
    public ConsumableBaseType(IBaseType owner)
    {
        _owner = owner;
    }
  
    public string SomeProperty
    {
        get { return _value; }
        set { _value = value; }
    }
  
    public void Foo()
    {
        Debug.Log("DID FOO!");
    }
  
}

Of course this doesn’t enforce that ‘IBaseType’ is a MonoBehaviour.

For this I usually use a contractual interface I call ‘IComponent’:

This way anything that implements it, must return some component for itself. May it be a wrapper, or a component itself.

3 Likes

Interfaces don’t help since they cannot contain fields or implementation. This would still result in common fields and functions being duplicated in the sub classes.

class BaseClass : MonoBehaviour
{
    public sting text { get; set; }

    protected void CommonFunction()
    {
         // Do stuff
    }

    protected virtual void UniqueFunction() { }

}

class SubClassA : BaseClass
{
   
     protected override void UniqueFunction()
     {
         // Do stuff unique to this sub class.
     }
}

class SubClassB : BaseClass, MaskableGraphic
{
 

     protected override void UniqueFunction()
     {
         // Do stuff unique to this sub class.
     }
}

P.S. @lordofduct I didn’t see your post until after I posted. Let me consider your post.

3 Likes

Note, in your situation as well… you don’t need to inherit from MaskableGraphic.

Since MaskableGraphic is itself a component, and implements itself in the same component design pattern that unity set up (which is a composite pattern in and of itself).

Instead you write your script as its own MonoBehaviour, and just include the ‘RequireComponent’ attribute on the script:

public class BaseType : MonoBehaviour
{
 
    // common functionality
 
}

public class SubClassA : BaseClass
{

    // Unique functionality & implementation

}

[RequireComponent(typeof(MaskableGraphic))]
public class SubClassB : BaseClass
{

    private MaskableGraphic _graphic;
 
    void Awake()
    {
        _graphic = this.GetComponent<MaskableGraphic>();
    }
 
    //unique functionality & implementation, with access to '_graphic'
 
}

This honestly is the heart of the ‘composite’ design pattern. It reduces large inheritance chains, and instead allows adding/removing functionality based on the consumed parts that each type may or may want/need.

See:

Unity just uses a modified version of the composite pattern usually called the ‘component pattern’ that is really common in the game design world.

2 Likes

Thanks to Unity’s components, I don’t really see the use case for multiple inheritance. At best, you can say it’s a method to copy functionality without physically copying it, and in cases where you would need more control over execution order in the case of dependent components. The role of polymorphism is basically taken care of by interfaces.

1 Like

I need to inherit from MaskableGraphic as my component makes use of the functionality included in this class. Also you cannot add MaskableGraphic using [RequireComponent] since it is an Abstract class. You get the following error when doing so “Can’t add script behaviour MaskableGraphic. The script class can’t be abstract!”

I also need to be able to use the GraphicRegistry.RegisterGraphicForCanvas(Canvas c, Graphic graphic).

That is not entirely true. But you have to be careful the order you have added components to the game object. If there is a mono behavior that already implements the abstract class attached to the game object when you add the component that requires it, RequireComponent doesnt cry. Not great, but might be useful information?

Does MaskableGraphic have to be abstract? If so you could try this:

public interface IMaskableGraphic
{
    void MaskableFunction();
}

public abstract class MaskableGraphic : MonoBehaviour, IMaskableGraphic
{
    public abstract void MaskableFunction();

    public virtual void CommonFunction() { }
}

// Component attached to GO's
public class TypeOfMaskable : MaskableGraphic
{
    public override void MaskableFunction() { }
}
public class BaseClass : MonoBehaviour { }

public class SubClassA : BaseClass { }

// TypeOfMaskable must be attached to same GO.
[RequireComponent(typeof(TypeOfMaskable))] // Optional
public class SubClassB : BaseClass
{
    private MaskableGraphic _maskable;

    void Awake()
    {
        _maskable = GetComponent<MaskableGraphic>();
    }

    void Function()
    {
        _maskable.MaskableFunction();
        _maskable.CommonFunction();
    }
}

It’s similar to lordofduct’s post #5, except the RequireComponent would change to requiring a TypeOfMaskable component.

MaskableGraphic is a Unity class so I can’t change it.

Here’s the thing. Multiple Inheritance of classes does NOT exist in C#.

You have to use interfaces.

To share implementation, you have to use some type of compositing to get it.

We’ve outlined multiple ways to consume shared implementation with interfaces.

We don’t know what exactly you want to do, so picking the BEST option is going to be difficult for us to do in our position of ignorance of your desires.

So… pick one. Give it a try.

Cause otherwise… you’re not going to get multiple inheritance.

1 Like

How about another example for you… and from the sounds of what you need, how I probably would go, but again… I’m not sure exactly what you’re attempting for.

interface IBaseClass
{

    void Foo();

}

class BaseClass : MonoBehaviour, IBaseClass
{

    public void Foo()
    {
 
    }

}

class SubClassA : BaseClass, IBaseClass
{

}

[RequireComponent(typeof(BaseClass))]
class SubClassB : MaskableGraphic, IBaseClass
{

    private IBaseClass _other;
 
    void Awake()
    {
        _other = this.GetComponent<IBaseClass>();
    }
 
    public void Foo()
    {
        _other.Foo();
    }

}

SubClassB takes on the same behaviour as another BaseClass, by consuming it, and can still be treating polymorphicly as a IBaseClass.

All of these suggestions though are all rooted in the same concept. It’s just the ordering of the compositing that’s changing around. You need to figure out the ordering that fits your needs.

If C# doesn’t support Multiple Inheritance. Then maybe try Javascript, though I’m not entirely sure if javascript does support it. Dunno Im really just eyeballing here :frowning:

Nope, unityscript (the dialect of javascript used in unity) does not support multiple inheritance either.

They both compile down to the same type of IL code to run in the Mono runtime. And the .Net/Mono runtime inherently does NOT support multiple inheritance of classes.

And there’s a very good reason why.

Multiple inheritance complicates the member inheritance chain.

Lets say for instance you have:

public class OddType
{

    public string Value
    {
        get;
        set;
    }

    public void Foo()
    {
        Debug.Log(this.Value);
    }
   
}

public class EvenType
{

    public int Value
    {
        get;
        set;
    }

    public void Foo()
    {
        Debug.Log(this.Value);
    }
   
}

public class NeutralType : OddType, EvenType
{

   

}


//.....

NeutralType obj = new NeutralType();
obj.Value = 5; //did I just set the string of OddType to "5" or the int of EvenType? Should it be type inferred?
obj.Value = "Hello"; //if it were type inferred, this would be legit then?
obj.Foo(); //so which gets printed to screen? 5, or "Hello"?

This is an issue that C++ multiple inheritance when dealing with abstract classes would have.

Most project terms would restrict multiple inheritance to empty abstract classes that had no implementation… effectively making them an ‘interface’. So as to avoid the implications of cross conflicts in the inheritance chain.

Java and C# removed this complexity when designing their languages opting for the more explicit ‘interface’ contract type. And to require compositing to share implementation.

2 Likes

Ya in my experience with c++ and multiple inheritance, it is never not fucked me. Works great if you are the only one on the team and can make sure there is no name clashing, and you got a effective way to pass data to the parents constructor. But with multiple people on the team it falls apart quick so i always just used it as a way to make fake interfaces.

All the suggestions have / are very valuable. I just need to experiment with these various options.

HI
i am trying to add multiple base classes in c#.
like in the example

using UnityEngine;

using System.Collections;
using Holoville.HOTween;


public class animateflaot : MonoBehaviour , valuebasecointainer

{
example code

}

when i try to add mono behavior and another script i get error but i have seen some scripts with multiple base classes.

if multiple base class was not possible how to add reference to another script so that i can add function from the valuebasecointainer can be called from the animateflaot script ?

Try just using a Component, or you can use an Interface.

Add a ValueBaseContainer (MonoBehaviour) component to the same GameObject.

public class AnimateFloat : MonoBehaviour {

    private ValueBaseContainer _valueBaseContainer;

    void Awake()
    {
        _valueBaseContainer = GetComponent<ValueBaseContainer>();

        _valueBaseContainer.FunctionName();
        _valueBaseContainer.AnotherFunction();
    }
}

Or you can make _valueBaseContainer public to click-drag a component from somewhere else into the inspector.

what if the reference script was a name space, i cannot drag and drop into object how to do it in that case.

Namespace? Interfaces have issues within Unity due to their lack of serialization. They cannot be referenced from script.

However in your case, just abstract ValueBaseContainer and inherit MonoBehaviour:

public abstract class ValueBaseContainer : MonoBehaviour
{
// abstract methods
}
public class animateflaot : ValueBaseContainer
{
// example code
}