parent constructors...up and up?

Not about OpenMW? Just about Morrowind in general? Have some random babble? Kindly direct it here.
Locked
User avatar
lgromanowski
Site Admin
Posts: 1151
Joined: 05 Aug 2011, 22:21
Location: Wroclaw, Poland
Github profile: https://github.com/lgromanowski
Contact:

parent constructors...up and up?

Post by lgromanowski » 22 Aug 2011, 21:17

Star-Demon wrote: Hey guys - working on some things and I managed to come back to something I wanted to work months ago in C# and XNA but never finished. Now I'm all confyuzlled.

Class Hierarchy looks like this:

1. Item -> Weapon -> Blade/Stick/etc
I also have a
2. ItemDB - which holds items.

Let's now say I want to construct me a ItemDB. It takes items.

Let's make items constructed as Blade, stick, etc - those objects in the ItemDB vector (err....List in C#) are references to places in memory, and methods called on those will be the actual type they were constructed as (the lowest classes). That's the idea -

So, When I construct a blade, I can use the base constructor in blades, which calls the base in Weapon...and then weapon's constructor then call Item's constructor. Basically, by providing all the right arguments as I go, I can go right up the chain?

Is this okay? I confused myself and now I'm not sure how this will work out - no one I know really knows C# better than I do, and I just picked it up and am trying something I haven't tried before.
Star-Demon wrote: Another confusing aspect

Code: Select all

        public Weapon(int cst, int w, String n, String desc, String i, String p, String modnum, int rng, 
            int clipS, int clipCur,float scope, float spread, float recoil, float kick, int cycdel)
            : base(cst, w, n, desc, i, p)
            //So basically, as I go down the constructors get more huge and I have to redefine them?
        {
                            
        
        }
What is so hard about just doing "base(argsgohere);" and continuing on my merry way?


EDIT: Phew! got it. Looks like it all works. It's messy but it works.
athile wrote: (Quick disclaimer: I know C++ much better than C#...)

Inheritance:

It sounds like you already figured it out, but the compiler calls every constructor in an inheritance chain. Let's say class C inherits from B which inherits from A. Conceptually, the compiler first constructs an object of type A (by calling that constructor), then calls B's constructor with the object that A created to 'add' the functionality of B, and then call's C's constructor to finish creating the object.

I don't know about C# exactly, but one interesting way to see that the compiler first constructs an object of type A is to use virtual methods. While in the constructor of A, the object *is* of type A (and has A's vtable), even though it will *eventually* be of type C. Anyway, trying examples like this should give you a good idea of what the compiler does:

Code: Select all

struct A
{
    A() { print(); }
    ~A() { print(); }
    virtual void print() { std::cout << "class A" << std::endl; }
};
struct B : public A
{
    B() { print(); }
    ~B() { print(); }
    virtual void print() { std::cout << "class B" << std::endl; }
};
struct C : public B
{
    C() { print(); }
    ~C() { print(); }
    virtual void print() { std::cout << "class C" << std::endl; }
};

void test()
{
    C* pObject = new C;
    delete pObject;
}


int 
main (int argc, char** argv)
{
    test();
    return 0;
}

The result is:

Code: Select all

class A
class B
class C
class C
class B
class A


Constructors with lots of arguments:

Yes, it can be a pain having constructors with lots of arguments - and if you write your code as you have, the number of arguments will only increase as the hierarchy gets deeper. One simple alternate approach is to initialize everything to a reasonable default in the constructor, but then expose changing these values via methods (or C# properties, I suppose):

Code: Select all

Weapon myWeapon = new Weapon();
myWeapon.Recoil = 17;
myWeapon.Kick = 11;
...
That way when you create a Blade, you actually don't have write any "duplicate" code to pass the constructor arguments. "Kick" and "Recoil" will be inherited directly into the child class. One could argue this is a less theoretically pure approach but more practical one.


Deep hierarchies for items:

You also say you were thinking Item -> Weapon -> Blade/Stick/etc. As far as I know (which is obviously limited), game engines often avoid deep hieracheries. For example, the hierarchy might stop at Weapon. Any Blade specific behavior or Stick specific behavior comes in a script or via some configuration of the Weapon. The rationale is that class hierarchies are generally a pain to change later in development and large hierarchies get confusing. Thinking only of code maintaneance, it's sometimes easier to have fewer, but more general and flexible classes. You also inevitably run into classes that seem to inherit *some* of class X and *some* of class Y (imagine a custom weapon that's half Spear and half Sword); the Composition design pattern can be helpful here rather than direct inheritance.

Again, there's no technical reason why you can't give every single type of Weapon it's own class, but - only speaking for myself - if it's a code base you're going to be developing for a long time, it's better make the engine more 'data driven' and use Composition over Inheritance, rather than coding it all into the hierarchy.
Star-Demon wrote: Huh. I never thought about it that way. Thanks for all that.


One solution is to have the generateDB() function add/construct objects according from streamed in input from an XML file based on their type. I've never used a file like that, but I Cn make hte XML file and make the loop part easily enough.

I'm happy it works, though. It means that, although messy, I now have have a single object that is now able to store all the items in a game, all data included for me no matter what they are or how they behave.

Now I can just send those to a player's inventory when I want one.

Although, now that I think about it, I'm not sure how to handle duplicates or stacks of an item in the player's inventory...

I don't think I'll go any deeper than WeaponType, but I think, at the time, I wasn't sure how to define a weapontype other than a strange, inpersonal integer, a messy string, or an Enum...

Since I've been working a lot in blender, the behavior of these really depends on what the object is. Meleeweapons don't create projectiles when "fired", you don't :reload" them, and so on...I suppose I was trying to be very organized.

I might be able to go one up and generalize a little more.

hey...wait a sec, maybe that is better idea...
Hircine wrote: hey,

for your inventory i would have a class that manages a collection of items
item being the superclass of everything that goes in the inventory.
then have a bool that determines if its stackable.
and a int that says how many there are. and within the inventory management class you can say how many can be in a stack. (a max)

your management class has a grid (like diablo or MW) or a list like Oblivion.
that holds all of these items.

anyway
hth.
best regards,
Lukasz

Locked

Who is online

Users browsing this forum: No registered users and 1 guest