Sign in to follow this  
Racky1275

[.net] Inheritance and Scope problem with my engine... In C#

Recommended Posts

Ok, I'm new to oop in general (still regard 68K Asm as my favorite language) and have got myself a little stuck... [rolleyes] I'm trying to implement a dictionary collection of graphic objects. Only cBox is implemented in this sample, the use of an abstract class makes it very easy to add cCircle, cSprite, etc. The Draw() method makes a call to the parent GraphicsDevice, but of course, it is out of scope. I realise it's the Dictionary limiting the scope of inheritance, but I don't know how to fix it. I've previously tried passing dxDevice as a parameter to the methods, but the code soon got messy. Unfortuneatly there's a few other things that are used globally, they're just not implemented in my sample. Any OOP gurus out there? [cool]
  class cSceneManager
  {
    private Dictionary<string, cSceneObject> dictObjects = new Dictionary<string, cSceneObject>();
    public GraphicsDevice dxDevice;

    public cSceneManager(GraphicsDevice device)
    {
      dxDevice = device;
    }

    public void Draw(string strSceneName)
    {
      foreach (cSceneObject SceneObject in dictObjects.Values)
      {
        SceneObject.Draw();
      }
    }

    public void AddBox(string name, int width, int height)
    {
      dictObjects.Add(new cBox(name, width, height);
    }
  }


  abstract class cSceneObject
  {
    public string strName;
    public abstract void Draw();
  }


  class cBox : cSceneObject 
  {
    public int intWidth;
    public int intHeight;

    public cBox(string name, int width, int height)
    {
      strName = name;
      intWidth = width;
      intHeight = height;
    }

    public override void Draw()
    {
      dXdevice.DrawBox(intWidth, intHeight);  // Out of scope!
    }
  }


[Edited by - Racky1275 on November 10, 2008 3:57:33 AM]

Share this post


Link to post
Share on other sites
In that exact situation I would pass dxDevice to the Draw calls inside cSceneManager's Draw function. One quick idea, in the case that multiple members are required you could put them all in a structure that could then be a member of cSceneManager. Then instead of passing them all alone pass that member to the draw functions.

Share this post


Link to post
Share on other sites
Quote:
Original post by Wolfdog
In that exact situation I would pass dxDevice to the Draw calls inside cSceneManager's Draw function. One quick idea, in the case that multiple members are required you could put them all in a structure that could then be a member of cSceneManager. Then instead of passing them all alone pass that member to the draw functions.


I'm with Wolfdog - I would make the Draw method take a structure, perhaps DrawContext, DrawParameters, etc. In it you would expose the dxDevice, which lets you make it private in the SceneManager class. By using a structure, you protect yourself from having to revisit all of the derived classes' Draw methods if you need to add additional information to the structure, like selected state, clip box, or anything.

I'm in favour of this kind of approach because it protects the manager from having to expose all of its members to the public, and instead controls when in the update loop specific subsystems and objects can be accessed. Often I have passed in a structure which actually contains only interfaces, so the client objects, like box, circle, etc, never actually see the dxDevice - instead they see an interface IDxDevice, which exposes only the properties and methods client code should ever worry about.


Share this post


Link to post
Share on other sites
Thanks for the help guys. You're right, passing a structure would be a great practical solution, but isn't there a more OOPy way of solving this problem. Maybe deriving a new type of Dictionary?

The 'reasoning' behind my obsession is that my actual engine uses a lot more layers, and you end up passing the structure quite a few times. This seemed inefficient when the code itself neatly defines a heirarchical structure, with things like dxDevice always at the top.

My graphics engine currently works, so this is more a theoretical exercise to help improve my OOP theory really. Solving the scope issue is part 1, finding a more generic way of adding cBox, cCircle, etc. was part 2. (thinking .Add(type, params...)

(I went overboard with my public's in the sample, but in practice would probably convert most of them to Protected's.)

Share this post


Link to post
Share on other sites
Passing the graphics device context into Draw calls is called Dependency Injection (providing the Draw call takes an interface, not an implementation). It's a perfectly valid way of doing things and won't contravene any OOPiness you seek.

Also, consider making your public fields private, rather than protected. This way, you can protect the data invariant in one place.

Share this post


Link to post
Share on other sites
Thanks Zdlr, I'm definately not questioning the wisdom of using DI, but this is more of a conceptual issue now... [headshake]

If your code describes a heirachical structure, then surely C# will allow you to use inheritance from top to bottom. It might not be particulary sensible in this case, but unless I can figure out how it's done then the whole concept of objects inheriting properties from parents is fairly broken.

Are we saying it is not possible with C#???

Share this post


Link to post
Share on other sites


interface ISceneObject
{
string Name
{
get;
}

IRenderContext RenderContext
{
get;
}

void Draw();
}


You could then provide concrete implementations for both the interfaces. RenderContext may be set on scene node construction and then it would have access to it during the Draw() call, without passing it through. This is also DI, just a different way around it.

Share this post


Link to post
Share on other sites
Thanks again Zdlr, but as you say, that's basically DI.

If I had a cCar class, and a cWheel class based on cCar, then cWheel could inherit the properties of cCar automatically. I could create as many cWheels as I like, but if I want to store them in a collection my inheritance is broken. I then have to start using DI to explicitly allow access to properties.

DI definately short circuits the problem, and like you say it's definately a valid technique, but there must be another way...

Sorry to be such a pain!

Share this post


Link to post
Share on other sites
A wheel inheriting from a car? Inheritance is an is-a relationship. I guess a wheel is not a car, but that a car has wheels? If you are seeking to share some properties, consider either some composition or inheriting from a third interface.

Share this post


Link to post
Share on other sites
I think you're assuming that inheritance is some sort of panacea. Generally, you should favour composition over inheritance, which is exactly what DI achieves. I'd look into evaluating your emphasis on inheritance.

Share this post


Link to post
Share on other sites

Ah yes, you see how new to this I am! I read it as a cWheel is-part-of a cCar.

In my world:
I never want to create a wheel in isolation.
A wheel is holding more specialised information about the car.
A wheel intrinsically knows which car it is connected to, by inheritance.
There are multiple wheels!

A collection of wheels would still need to know which car they are individually connected to.

Now I just sound like a raving lunatic... Great.

Share this post


Link to post
Share on other sites
Quote:

I never want to create a wheel in isolation.


This is a textbook example of objection composition. The car is entirely responsible for its wheels - the latter cannot exist without the former. In the real world, of course, a wheel could be independent of a car, but it's a question of what you are modelling.

Quote:

A wheel is holding more specialised information about the car.


Such as friction, for example? Friction of a wheel could be a function of its wear and tear and other real-world properties. The overall friction force acting on the car is then a function of all of its wheels friction, and likely other properties.

Quote:

A wheel intrinsically knows which car it is connected to, by inheritance.


It would be better to avoid inheritance and to pass the car in to the wheel's constructor so that the wheel knows about its parent.

Quote:

There are multiple wheels!


Absolutely, do you restrict yourself to four at all times, or do you use a List<Wheel> (or similar container) to keep track of them? That way, you could actually lose a wheel or model a big 6-wheel artic' truck.

Example:



class Car
{
public decimal Friction
{
get { return Wheels.Average(w => w.Friction); }
}

private List<Wheel> Wheels
{
get;
set;
}

public void AddWheel()
{
Wheels.Add(new Wheel(this));
}
}

private class Wheel
{
public Wheel(Car parent)
{
Parent = parent;
}

public decimal Friction
{
get { return 1.0f - Wear; }
}

public decimal Wear
{
get;
set;
}

public Car Parent
{
get;
private set;
}
}

Share this post


Link to post
Share on other sites
It's beginning to look like these OOP techniques aren't quite as useful as I had imagined... which is a pity really.

An awful lot of my code depends on strict heirarchical structures, making inheritance seem like it truely is a panacea!

Using DI to short-cut pathways from the top to the bottom of my code tree seems messy, but I'll bow to your collective experience and follow the pattern...

Thanks for the help guys. [smile]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this