I’m working with a couple of classes that use inheritance, and I can’t figure out how to get access to methods and variables in a child class when working with the parent type.
I’m not sure my phrasing here is quite right so here is an example of what I’m doing:
public class ParentClass : ScriptableObject
{
}
public class ChildClass : ParentClass
{
public variable;
public void Method()
{
}
}
Then I have this script:
public class Manager : MonoBehaviour
{
public void FindMethod(List<ParentClass> parentClassList)
{
foreach (ParentClass parent in parentClassList)
{
if (parent is ChildClass)
{
// Here is where I want to access the child class methods and variables
}
}
}
}
I have a Debug.Log
going where the commented code is and it’s working as intended so that it only the parents that are the ChildClass
type are getting printed to the console, but I don’t know how to actually access the methods and variables once I know that that particular parent is a ChildClass
.
public class Manager : MonoBehaviour
{
public void FindMethod(List<ParentClass> parentClassList)
{
foreach (ParentClass parent in parentClassList)
{
if (parent is ChildClass child)
{
child.variable = bologna;
// Here is where I want to access the child class methods and variables
}
}
}
}
While it’s totally valid code to do this - I would recommend trying as much as possible to not do this! Instead of directly accessing variables from the child class and doing something, consider creating a virtual DoSomething() method on the parent class and have th child class do its own implementation. That’s kind of the ideal polymoprhism situation:
public class ParentClass : ScriptableObject
{
public virtual void DoSomething()
{
}
}
public class ChildClass : ParentClass
{
public int variable;
public override void DoSomething()
{
print("Variable value is " + variable);
}
}
Then your manager code just looks like this:
public class Manager : MonoBehaviour
{
public void FindMethod(List<ParentClass> parentClassList)
{
foreach (ParentClass parent in parentClassList)
{
parent.DoSomething();
}
}
}
1 Like
@PraetorBlue
Thanks a lot for the help! I also found as I was trying out what you suggested that I can cast the parent as the child like this:
if (parent is ChildClass)
{
ChildClass child = (ChildClass)parent;
}
Which is what I was trying to do before, but I was doing it wrong haha. However I like how you did it better, where you created a child variable in the if statement, didn’t know I could do that!.
In regards to the virtual methods. I like this solution, my only concern is that the parent class will end up with a lot of virtual methods, because, unless I’m understanding you incorrectly, it’ll need to have different virtual methods for all the methods of each child class.
At that point, I guess if the child classes are similar enough they could have different overrides for the same method, but if they differ a lot I’m not sure how I would structure that.
EDIT: Also I’m not sure how I would access variables that are only available in the child class using virtual methods.
1 Like
Virtual implies that a derived class can overwrite it’s functionality.
Consider the following example:
public class BaseClass{
public virtual void DoSomething(){
Debug.Log("Base Class");
}
}
public class DerivedClass : BaseClass{
public override void DoSomething(){
Debug.Log("Derived class");
}
public void DoSomethingElse(){
Debug.Log("Not possible on base class");
}
}
And let’s say somewhere in my code I have a List.
List<BaseClass> allObjects = new List<BaseClass>();
allObjects.Add(new BaseClass());
allObjects.Add(new DerivedClass());
// Will output the following:
// Base Class
// Derived Class
for(int i = 0 ; i < allObjects.Count ; i++){
allObjects[i].DoSomething();
}
//This will not compile because DoSomethingElse does not exist on BaseClass
for(int i = 0 ; i < allObjects.Count ; i++){
allObjects[i].DoSomethingElse();
}
For example in my game I have a base class Creature, and a derived class called PastureAnimal. My Creature has a virtual method for Kill, because every creature can be killed. Each creature might implement this differently, some might play an animation on death, some might explode, some might drop some loot.
However only my pasture animals have a Collect method on them because not all creature can give you periodic items (milk, eggs, wool, etc).
So in this sense if I know I’m going to be collecting some resource from a living animal I know I’m only dealing with PastureAnimal. In this sense there is no point in putting a virtual Collect() method in the Creature class. Instead I just try to cast the Creature to PastureAnimal and if it works then I call Collect on it.
If I just want to Kill an animal then I don’t care if it’s a creature, a predator, a pasture animal etc. I just call Creature.Kill() and the system will know which to call.
1 Like
@ensiferum888
Thanks for the reply, so I think you’re confirming what I was thinking, that if I have a list of the ParentClass and I want to access info from the ChildClass IF the ParentClass has is a ChildClass, then a cast is the best solution?
It all depends on your architecture, there are hundreds of ways to do this “the right way”.
Like I said, if the functionality makes sense on the base class, go with a virtual method that you override when needed.
For example Animal → Mammal and Animal → Fish
You can imagine having a Breathe() method on the Animal class, and the mammal and the fish will have different implementations of that method. In this case you’d put a virtual Breathe method in Animal and overwrite it in the child classes.
If the function you want to call only makes sense for the ChildClass then leave it there and try to cast from Parent to Child to see if you can call the function.
For example Vehicle → Car and Vehicle → Plane
It makes no sense having a Land() function on the vehicle because most vehicles will never need that. The plane does however. In this case you would just declare the Land function in the Plane class.
Last resort would be to instead use interfaces and keep a list of interface instead. For example you could have multiple objects in your program that need to return a color, and you want to be able to call those without knowing what Type the object is you can use interfaces:
For example Animal, Vehicle and Building
public interface IHasColor{
Color GetColor();
}
public class SomeObject : IHasColor{
public int index;
public Color objColor;
[...]
public Color GetColor(){
return objColor;
}
}
List<IHasColor> colorThings;
for(int i = 0 ; i < colorThings.Count ; i++){
Debug.Log(colorThings.GetColor());
}
2 Likes