Thread: Cast a parent class to child

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    Feb 2011
    Posts
    5

    Cast a parent class to child

    It would seem my problem should have a nice simple solution, but I just can't find the syntax for it. First here's my code (simplified for the purpose of this problem):

    Code:
    public class Class1  {
    
      public int myVar = 1;
    
      private void LinkMe() {
        Test.Instance.LinkMe(this);
      }
    }
    
    public class Class2  {
    
      public int myVar = 2;
    
      private void LinkMe() {
        Test.Instance.LinkMe(this);
      }
    }
    
    public class Test  { // this is a singleton
    
      private static Test instance;
    	
      public void LinkMe(object obj) {
        Debug.Log(obj.GetType()); // Outputs "Class1", "Class2" ...
        Debug.Log(obj.myVar1); // gives error: "Type `object' does not contain a definition for `myVar' 
      }
    	
      public static Test Instance {
        get {
          if (instance == null) {
            instance = new Test();
          }
          return instance;
        }
      }
    }
    What I really want here is to pass different classes (in my example I only made Class1 and Class2) to one method in Test. The classes all share one variable called myVar which I want to access in Test. Since the argument of LinkMe method must have only one type, I use a parent class (namely object) of the classes calling the method.

    Now, in Test it seems LinkMe knows which type of class it gets passed, since that is what GetType() outputs. But when assuming this and trying to access myVar it suddenly acts as it was just an object and not what GetType() said it was.

    All I really wanna do here is get access to that variable myVar, but I can't find the right syntax for it. I tried something like this:

    Code:
    Type realType = obj.GetType();
    realType myClass = (realType) obj;
    myClass.myVar = 2;
    ..which of course doesn't work. So is there a way to do this simple?

    Note: I want to solve this without extending Class1, Class2, etc and without having to use manually the names of Class1, Class2, etc.

  2. #2
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    If any class that you're going to pass to Test.LinkMe() is guaranteed to have a myVar1 field or property, then you should be using a parent class or interface that has that field/property in it:
    Code:
    interface iMyVar
    {
      int myVar1;
    }
    
    class Test
    {
      ...
    
      public void LinkMe(iMyVar obj)
      {
        Debug.Log(obj.myVar1);
      }
    }
    And then just have your Class1 and Class2 implement that iMyVar interface.
    If you understand what you're doing, you're not learning anything.

  3. #3
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Differentiate runtime actions and compile time actions.

    The solution proposed above is a compile time action, you simply design better your classes to do what you want.

    For a run-time solution, you can use Reflection, haven't really bothered with it.

    In .NET 4.0 there is a "dynamic" keyword which makes things simple:
    Code:
    dynamic myClass = obj;
    myClass.myVar = 2;
    no idea if this works as it is, but you can do something between these lines. Basically the type will be resolved at run-time as well as the variable/method/property called (maybe it doesn't work with variables only with properties/methods).

  4. #4
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Quote Originally Posted by C_ntua View Post
    The solution proposed above is a compile time action, you simply design better your classes to do what you want.

    For a run-time solution, you can use Reflection, haven't really bothered with it.

    In .NET 4.0 there is a "dynamic" keyword which makes things simple:
    Code:
    dynamic myClass = obj;
    myClass.myVar = 2;
    no idea if this works as it is, but you can do something between these lines. Basically the type will be resolved at run-time as well as the variable/method/property called (maybe it doesn't work with variables only with properties/methods).
    You are correct that reflection and dynamic typing would work. However, I'd recommend against that in this case -- the original poster's issues are arising from badly designed classes. There are very good uses of both reflection and dynamic typing, but neither should be used as a bandaid to cover up poor design.

    In general, if you're trying to cast a base class to one of a group of derived classes, more likely than not it's your design that is wrong. That's certainly not an absolute rule, but if you find yourself thinking you need to do it, that should be a red flag to reconsider your design before moving forward.
    Last edited by Cat; 02-26-2011 at 02:42 PM.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  5. #5
    Registered User
    Join Date
    Feb 2011
    Posts
    5
    First let me just say I'm using Unity3d (a game editor that uses C# Mono 2.6 implementation), and I'm not sure that supports dynamic.

    OK, basically my design is something like this:


    I have a Manager.cs that is central to my whole structure. This is a singleton. When I want to get access to instances of classes, I would call the Manager which I wanted to have an array over all instances of classes that are available. So for example if I wanted to access Class1 from Class2 I would do something like this:

    Code:
    // in Class2
    Class1 class1 = Manager.GetLink("class1");
    class1.doSomething();
    And the problem I was faced with was when I was "linking in" my classes and storing them in the Manager singleton.

    Even if I make Class1, Class2... extend another class which I would then send to LinkMe in Manager, I would face the same problem when trying to use Class1 from Class2. I need a pointer array in Manager that points to the actual class!

    Any advice as to how to structure this?

  6. #6
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Quote Originally Posted by snowcore View Post
    Even if I make Class1, Class2... extend another class which I would then send to LinkMe in Manager, I would face the same problem when trying to use Class1 from Class2. I need a pointer array in Manager that points to the actual class
    What if you used generics?
    Code:
    class ClassBase
    {
      public int var1;
    }
    
    class Class1: ClassBase
    {
      void DoSomethingWithClass2()
      {
        Class2 obj = Manager.Get<Class2>(...);
      }
    }
    
    class Class2: ClassBase
    {
    }
    
    class Manager
    {
      private static List<ClassBase> _List;
    
      public static void LinkMe(ClassBase obj)
      {
        _List.Add(obj);
      }
    
      public static T Get<T>(string className)
      {
          // Return the object from the _List that matches
      }
    }
    Maybe I'm still confused about what you're trying to do.
    If you understand what you're doing, you're not learning anything.

  7. #7
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Quote Originally Posted by snowcore View Post
    Even if I make Class1, Class2... extend another class which I would then send to LinkMe in Manager, I would face the same problem when trying to use Class1 from Class2. I need a pointer array in Manager that points to the actual class!
    First, you're talking about arrays of objects, not classes. A class is a blueprint; an object is a particular constructed instance from that blueprint. The difference between a class and an object is the difference between a recipe and a cake.

    Second, you can accomplish this with a base class and any type of collection. That's not unusual. You can cast base pointers to derived pointers all the time. What threw up flags in your initial post was that you indicated that you didn't know the type you wanted at compile time. This in particular was a major flag:

    without having to use manually the names of Class1, Class2, etc.
    You should either know the name of the class OR (better) the name of an interface it implements at compile time. Then you cast to the interface and call methods on that.

    For example, in a game, if I had objects that could take damage, I might implement an IDamageable interface for every such class. Then I could take my base class pointer and cast it to that interface.





    Edit: I also have to wonder - you have a game where you have only one instance of each class??? I can't fathom how such a design would work. You basically just made your classes all singletons via a very convoluted process.

    I think rather than post code, you should post your design documentation (what classes do you have, how do they interact, what methods and properties do they have) and go from there. I'm still smelling a lot of smoke on this project of yours, and I think it's the underlying design that is the problem. This really ISN'T a common scenario, and that alone should be enough pause to consider if there should be design changes.
    Last edited by Cat; 03-02-2011 at 08:15 PM.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  8. #8
    Registered User
    Join Date
    Feb 2011
    Posts
    5
    I'm not very familiar with generics, I looked at some tutorials, but couldn't quite wrap my head around it. I tried implementing your code as well, but got an error regarding the line:

    private static List<ClassBase> _List;
    Error: The type or namespace name `List`1' could not be found. Are you missing a using directive or an assembly reference?

    I've tried to solve this structure problem for over 2 weeks now, and I'm just about to give up, cause it's driving me mad. I'll give one more example to try to explain what I try to achieve. I would think this is a common scenario that someone have a solution to, but maybe not.

    Code:
    public class Master {
    
      private static Master instance;
      public Class1 class1;
      public Class2 class2;
    
      public void LinkClass1(Class1 c) {
        class1 = c;
      }
    
      public void LinkClass2(Class2 c) {
        class2 = c;
      }
    
      public static Master Instance {
        get {
           if (instance == null) instance = new Master();
           return instance;
        }
    }
    
    public class Class1 {
    
      private Class1() {
        Master.Instance.LinkClass1(this);
      }
    
      private void DoSomethingInClass2() {
        Master.Instance.class2.SomeMethodInClass2();
      }
    }
    
    public class Class2 {
    
      private Class2() {
        Master.Instance.LinkClass2(this);
      }
    
      private void DoSomethingInClass1() {
        Master.Instance.class1.SomeMethodInClass1();
      }
    }
    This works fine, and this is what I want to do. But it speaks for itself that when we have 10 or more classes to link in, this "manual" way of doing it is really a pain. I have been trying to create an array in Master to contain all linked classes, that is the core issue here. So if this cast new light to my problem, please don't hesitate to suggest a solution

  9. #9
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    I would do something like this...

    Master.cs:
    Code:
        public class Master
        {
            private static Master _Instance;
            public static Master Instance { get { if (_Instance == null) _Instance = new Master(); return _Instance; } }
    
            private List<BaseClass> _ObjectList = new List<BaseClass>();
    
            public void LinkIn(BaseClass obj)
            {
                for(int i = 0;i < _ObjectList.Count;++i)
                {
                    if (_ObjectList[i].GetType() == obj.GetType())
                    {
                        _ObjectList.RemoveAt(i);
                        break;
                    }
                }
    
                _ObjectList.Add(obj);
            }
    
            public T GetObject<T>() where T: BaseClass
            {
                foreach (BaseClass o in _ObjectList)
                    if (o is T)
                        return o as T;
                return null;
            }
        }
    BaseClass.cs:
    Code:
        public class BaseClass
        {
        }
    Class1:
    Code:
        public class Class1: BaseClass
        {
            public Class1()
            {
                Master.Instance.LinkIn(this);
            }
    
            public void DoSomethingInClass2()
            {
                Class2 obj = Master.Instance.GetObject<Class2>();
                // Do stuff with the Class2 obj
            }
        }
    Class2:
    Code:
        public class Class2: BaseClass
        {
            public Class2()
            {
                Master.Instance.LinkIn(this);
            }
    
            public void DoSomethingInClass1()
            {
                Class1 obj = Master.Instance.GetObject<Class1>();
                // Do stuff with the Class1 obj
            }
        }
    I did this in VS 2010 and it worked great. I don't know much about the Mono feature set, but generics have been around since C# 2.0, so I'm guessing Mono supports them by now.

    NOTE: If your classes already need to be derived from another base class, then the BaseClass that I made can simply be turned into an interface instead.
    Last edited by itsme86; 03-01-2011 at 10:32 AM.
    If you understand what you're doing, you're not learning anything.

  10. #10
    Registered User
    Join Date
    Feb 2011
    Posts
    5
    @itsme86: You are my savior! That worked very nice indeed, beautiful!

    I made a small enhancement to the Master.cs:

    Code:
    public class Master {
      private static Master _Instance;
      public static Master Instance { get { if (_Instance == null) _Instance = new Master(); return _Instance; } }
    
      // private List<BaseClass> _ObjectList = new List<BaseClass>();
      private Dictionary<string, BaseClass> _ObjectList = new Dictionary<string, BaseClass>();
    
      public void LinkIn(BaseClass obj) {
        // Do I really need this?
        // for(int i = 0;i < _ObjectList.Count;++i) {
        //   if (_ObjectList[i].GetType() == obj.GetType()) {
        //     _ObjectList.RemoveAt(i);
        //     break;
        //   }
        // }
    
        _ObjectList.Add(obj.GetType().ToString(), obj);
      }
    
      public T GetObject<T>() where T: BaseClass {
        return _ObjectList[typeof(T).ToString()] as T;
      }
    }
    This also worked, and I don't have to go through a list with foreach. I wonder, the stuff i commented out, that is just a check so that i don't link a class twice yes? If so I don't really need it in my case.

    Thanks a lot!

  11. #11
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Quote Originally Posted by snowcore View Post
    I wonder, the stuff i commented out, that is just a check so that i don't link a class twice yes? If so I don't really need it in my case.

    Thanks a lot!
    Yup, that's all it was doing. If you don't need to check that then you can leave it out. Glad it worked out for you.
    If you understand what you're doing, you're not learning anything.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  2. Windows Form App as parent, Directx as child??
    By yetti82 in forum C++ Programming
    Replies: 3
    Last Post: 05-29-2006, 03:04 AM
  3. child classes calling parent constructors (with arguments)
    By reanimated in forum C++ Programming
    Replies: 3
    Last Post: 05-01-2006, 10:52 AM
  4. structure vs class
    By sana in forum C++ Programming
    Replies: 13
    Last Post: 12-02-2002, 07:18 AM