Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Should I inherit components?

Discussion in 'Scripting' started by nicklowkc1, Jan 10, 2021.

  1. nicklowkc1

    nicklowkc1

    Joined:
    Feb 27, 2019
    Posts:
    28
    Let's say I have a base component named "BaseJob" that has some protected variables that it's child could inherit from. And then I have something like "Warrior", "Mage" that inherit BaseJob components so I can drag it into the inspector and do something like getcomponent. Is this a good design?
    I got some weird result below:
    Parent.cs
    Code (CSharp):
    1. public class Parent : MonoBehaviour
    2. {
    3.     protected int baseNumber = 1;
    4.     public new int BaseNumber { get { return baseNumber; } }
    5.     private void Start( )
    6.     {      
    7.         Debug.Log( "Parent baseNumber = " + baseNumber );
    8.     }
    9. }
    Child.cs
    Code (CSharp):
    1. public class Child : Parent
    2. {
    3.     public new int BaseNumber { get { return baseNumber; } }
    4.     // Start is called before the first frame update
    5.     void Start()
    6.     {
    7.         baseNumber = 10;
    8.         Debug.Log( "Child baseNumber = " + baseNumber );
    9.         Debug.Log( "Child base.baseNumber = " + base.baseNumber );
    10.     }  
    11. }
    and GetParent.cs
    Code (CSharp):
    1. public class GetParent : MonoBehaviour
    2. {
    3.     [SerializeField] Parent parent;
    4.  
    5.     // Start is called before the first frame update
    6.     void Start()
    7.     {
    8.         Debug.Log( "parent.BaseNumber = " + parent.BaseNumber);  
    9.     }
    10. }
    And the debug.log result is the following:
    parent.BaseNumber = 1
    Child.baseNumber = 10
    Child.base.baseNumber = 10

    I am assuming the parent.BaseNumber should be 10 but I got 1. Shouldn't it be 10 instead?
     
  2. AriyaSD

    AriyaSD

    Joined:
    Nov 2, 2019
    Posts:
    24
    I'm pretty sure this is happening because GetParent's Start() is being called before Child's. Meaning that when parent.BaseNumber is printed, baseNumber hasn't been set to 10 yet.
     
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,531
    No, that's not how inheritance work. A child class can not choose to inherit something or not. The child is always inheriting everything with no exception from the parent.

    The issue you're seeing is what AriyaSD told you. The different Start methods of different classes are called in "some" order. In your case Start of your GetParent class seems to be executed before Start of your Child class. This order can be changed with the ScriptExecution order in the project settings. However that is never a good idea if you can avoid it. In general you should always use Awake to initialize the object itself and use Start when you have to interact between components for some initialization. Apart from that initializing a private or protected primitive type variable in code could be done from the constructor to ensure the wanted value is present at any time (except in the constructor of the parent since that always runs before the child's).

    Next thing that is weird is your use of the new keyword and your redeclaration of your property. You should never use the new keyword on member delcarations unless you have a really good reason. Though member hiding should be avoided at all cost because your class will become a "frankenstein". So depending the variable type you may see / access different members from outside. So don't use it. If you want to declare a property in the base class that can be overridden you have to declare it as virtual and use the override keyword in the derived class. However in your case both of your property implementations do exactly the same thing, so it's pointless to redeclare or override the property if you don't change any of the code in the getter.

    Next inside your Start of your Child class you have two debug log statements. Once you read "base.baseNumber" and in the other you read "baseNumber". Both will access the exact same variable. Using base makes only sense for members that have been overridden or hidden.
     
  4. nicklowkc1

    nicklowkc1

    Joined:
    Feb 27, 2019
    Posts:
    28
    But even I update the Debug.log on GetParent's update, it still show that parent.BaseNumber is equal to 1. I have put my baseNumber code in Awake() of the Child class, yet I still get the same result.
     
  5. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    You should make the start method protected virtual and from sub class override and make sure not to call base.Start

    Though I don't think you should overuse inheritance in components
     
    Bunny83 likes this.
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,531
    That's not possible unless you have an actual instance of your Parent class. Are you sure you don't have an additional instance of your parent class attached somewhere? In other words are you sure you only have your Child class attached to a gameobject in the scene and you dragged this child instance onto the parent field of your GetParent class? If not I have the suspicion that you don't really understand what inheritance is all about ^^.
     
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,531
    I just want to add that I'm actually with MDADigital and that you should not overuse inheritance as the component design is specifically to have flat class hierarchies. You should have a good reason to use inheritance.
     
  8. nicklowkc1

    nicklowkc1

    Joined:
    Feb 27, 2019
    Posts:
    28
    Hi, it seems like I drag the wrong gameobject to my getparent thats why I got the difference result..