Thread: Cast a parent class to child

  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
    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

  8. #8
    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.

  9. #9
    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!

  10. #10
    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.

  11. #11
    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.

  12. #12
    Registered User
    Join Date
    Feb 2011
    Posts
    5
    @Cat: Thanks for your feedback! I will elaborate a little here.

    First, I was a bit sloppy with my language, sorry about that. I do know the difference between classes and objects and have been working with OOP for quite some time (but mostly in php and actionscript). Though I now see that reading through my thread here I do seem like a total rookie ;]

    Anyway, about my design keep in mind that I'm programming C# in Unity3D and that means I'm working with lots of game objects which one can attach "components/scripts" which can be written in C#. Without any need to know the details, I will try to shortly describe my design:

    I only have one singleton, which keeps data and methods that are used throughout the game. In Unity3D you work with "scenes" (kind of like levels), and when going to and from scenes, all objects "on stage" will be wiped to make way for the next scene. Therefor I need this master singleton to keep track of stuff between scenes among other things.

    In a scene I would have many game objects with components (which are basically C# scripts/classes). Many elements (or objects if you like) in a game only need one class to manage them, ie a Shop.cs class that would manage the one and only shop, etc.. All these objects in the game usually need to talk to each other. So instead of passing links from and to all these individual objects, I make them call LinkMe in my singleton, and that makes all objects reachable from my singleton "central".

    Doesn't this make sense?

  13. #13
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Yes, this is a common scheme and I like it myself.
    But I think you are then generalizing you code without a reason.
    Think: do you need to know the exact type of an object?

    For example you want to save a scene which can have various objects. Lets say you have a "Mall", "Shop", "Mountain" as a scene. You can save them all in a List<object> which will be a member of the Master Class. Then since you know what classes are available you can simply have a code like

    Code:
    class Master {
       List<object> AllObjects;
       ....
       int CountPeopleInPrevScene()
       {
              int sum = 0;
              foreach(object o in AllObjects) {
                    if (o is Mall)
                    {
                         Mall m = (Mall)o;
                         sum += m.CountPeople();
                    }
                    else if (o is Shop)
                   {
                         Shop p = (Shop )o;
                         sum += p.CountPeople();
                    }
              }
       }
       ...
    }
    not that the "is" oeprator checks the class. So in this case, do you need to know what the type of the object is? No, you just care if it is a "Shop" or "Mall". If you later on add another object "Clown", you won't have to worry about it in this method.

    Of course, if you had this method you can use a "Building" as a base class and have only
    Code:
    if (o is Building)
    {
        ...
    }
    and whatever new class you add you can handle without changing the code.

    If you want to optimize you can have separate lits, one for each class or one for each class.

    NOTE: even if you could use "dynamic", which I think you cannot on this version, you would just get the type of class. What good does that do you if you cannot use it? If you can use it that means you know its methods, thus the class.
    There are some uses for it, but if this is what you are trying to do, this is not the case.
    A use would be if you had
    Code:
    Class A
    {
        void Do(Building b) {}
        void Do(Human c) {}
    }
    and then you wanted to pass an object to Do where you don't know what the available classes are or what Do actually does or you simply don't want to lose time researching for this things. So in order to call the correct Do() function you would need to resolve its type.

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