Sign in to follow this  

[C#] Creating new instances using Polymorphism

This topic is 3098 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a class that inherits from another class, in this case Bullet is the base class and PistolAmmoNormal is the class that inherits from Bullet. Is it possible to pass base type Bullet into a class and then create a new instance based on what type of Bullet was passed in? For example:
// Current type of bullet is PistolAmmoNormal
PistolAmmoNormal bullet_Current;
// Generate all possible instances for that type
bullet_CurrentList = bullet_Manager.GenerateAllBullets(bullet_Current);

        public List<Bullet> GenerateAllBullets(Bullet bullet_Current)
        {
            bullet_Current = new WhatEverTheTypeOfBulletBeingPassedInIs(); 

.....
I hope that made sense. Thank you guys.

Share this post


Link to post
Share on other sites
I'm not really sure what you're trying to achieve here. If you want a method that creates a List<> of Base, you could use a generic function like this




List<Bullet> GenerateAllBullets<BulletSubType>(int numBullets)
// generic constraint: BulletSubType must derive from Bullet and have a default constructor
where BulletSubType : Bullet, new()
{
List<Bullet> bulletList = new List<Bullet>();
for (int i = 0; i < numBullets; ++i)
{
bulletList.Add(new BulletSubType());
}
}




If you provide more detail as to what you actually want, we might be able to help more.

Share this post


Link to post
Share on other sites
You can use reflection to do what you want.

using System;
using System.Reflection;

namespace CSharpTest
{
class Base
{
public readonly string type;
public readonly string name;

protected Base(string type, string name)
{ this.type = type; this.name = name; }
}

class DerivedA : Base
{
public DerivedA(string name)
: base("A", name)
{}
}

class DerivedB : Base
{
public DerivedB(string name)
: base("B", name)
{}
}

static class Program
{
static Base createOfType(Base obj)
{
Type passedType = obj.GetType();
Type stringType = "".GetType();

Type[] parameterTypes = { stringType };
ConstructorInfo ci = passedType.GetConstructor(parameterTypes);

object[] parameters = { "Bar" };
return (Base)ci.Invoke(parameters);
}

static void Main(string[] args)
{
DerivedA obj = new DerivedA("Foo");

Base newObj = createOfType(obj);
Console.WriteLine(newObj.type);
Console.WriteLine(newObj.name);
}
}
}


But there is probably a better design that avoids needing to do this.

Share this post


Link to post
Share on other sites
Sorry guys.

What I would like is to create a new instance of PistolAmmoNormal inside the GenerateAllBullets. Exactly the same as:


bullet_Current = new PistolAmmoNormal();


However, I want to pass the in bullet_Current as type Bullet. The type of Bullet in this case PistolAmmoNormal would create a new PistolAmmoNormal, if the type of bullet was PistolAmmoFlammable then a new instance of PistolAmmoFlammable would be created.


bullet_Current = new PistolAmmoFlammable();


I was wondering if there was a good way of doing this automatically depending on type?!

Share this post


Link to post
Share on other sites
Quote:
Original post by TheUnbeliever
You can use reflection to do what you want.

*** Source Snippet Removed ***

But there is probably a better design that avoids needing to do this.


Why would you use reflection? What's wrong with either a generic approach or a polymorphic Create method?

i.e

public class Bullet
{
abstract Bullet Create();
}

public class PistolAmmoNormal
{
Bullet Create()
{
return new PistolAmmoNormal();
}
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Spa8nky
I was wondering if there was a good way of doing this automatically depending on type?!


This is what my code does. Copy and paste it, and try switching the type of 'obj' in Main from DerivedA to DerivedB.

Share this post


Link to post
Share on other sites
Quote:
Original post by TheUnbeliever
Quote:
Original post by ChaosEngine
Why would you use reflection? What's wrong with either a generic approach or a polymorphic Create method?


Er, because I'm an idiot.


Lol, I wouldn't say that at all. Your solution will certainly work and is probably the most flexible approach. There might be an easier way, that's all.

To the OP, can you post a complete example of what you want. Don't just post 1 or 2 lines, show the entire function and an example of calling it.

Why do you want to pass in an instance of the type?

You've been given 3 solutions already, do any of them fit?

You could also do

Bullet CreateBulletOfSameType<BulletSubType>(BulletSubType bullet)
where BulletSubType : Bullet, new()
{
return new BulletSubType();
}


this will work if you have

PistolAmmoNormal bullet = null;
Bullet bulletCurrent = CreateBulletOfSameType(bullet);
// bulletCurrent is a PistolAmmoNormal


but not

Bullet bullet = new PistolAmmoNormal;
Bullet bulletCurrent = CreateBulletOfSameType(bullet);
// bulletCurrent is a Bullet

Share this post


Link to post
Share on other sites
Of course, that makes sense now.

ChaosEngine's method is precisely what I am after.

However why would I use abstract instead of virtual and override, is it a faster way of implementing the same thing?

E.G.




public class Bullet
{
public virtual Bullet Create();
}

public class PistolAmmoNormal
{
public override Bullet Create()
{
return new PistolAmmoNormal();
}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Spa8nky
Of course, that makes sense now.

ChaosEngine's method is precisely what I am after.

However why would I use abstract instead of virtual and override, is it a faster way of implementing the same thing?
[/code]


It's nothing to do with speed. If you have a virtual method you have to provide an implementation of it. If Bullet is a valid concrete class in your code, then use virtual i.e.


public class Bullet
{
public virtual Bullet Create()
{
return new Bullet();
}
}


However if every type of bullet must be a sub-class then use abstract.


Share this post


Link to post
Share on other sites
Quote:


However if every type of bullet must be a sub-class then use abstract.



Thanks for your help. Just wanted to clarify one thing.

Here is the class, as it stands at the moment:



public class Bullet : IQuad, IOcTree
{
public int damage; // How much damage the weapon inflicts (Multiply it by a factor for different parts of the body [E.G. HeadShot = damage * 3])
public CD_Ray ray; // The path the ammunition will follow (used for collision)
public float speed;

// IQuad related parameters
string IQuad.Effect { get { return effect_Type; } }
float IQuad.Height { get { return height; } }
int IQuad.Index_Indices { get { return index_Indices; } }
int IQuad.Index_Vertices { get { return index_Vertices; } }
ushort IQuad.Texture { get { return texture; } }
float IQuad.Width { get { return width; } }

public string effect_Type;
public float height;
public int index_Indices;
public int index_Vertices;
public ushort texture;
public float width;

// IOcTree related parameters
CD_AxisAlignedBoundingBox? IOcTree.Collision_AABB { get { return collision_AABB; } }
CD_BoundingSphere? IOcTree.Collision_BoundingSphere { get { return collision_BoundingSphere; } }
bool IOcTree.IsAlive { get { return isAlive; } }
bool IOcTree.IsOcTreeUpdatable { get { return isOcTreeUpdatable; } }
Vector3 IOcTree.Position_Current { get { return position_Current; } }
Vector3 IOcTree.Position_Last { get { return position_Last; } }

public CD_AxisAlignedBoundingBox? collision_AABB;
public CD_BoundingSphere? collision_BoundingSphere = null;
public bool isAlive;
public bool isOcTreeUpdatable;
public Vector3 position_Current;
public Vector3 position_Last;

public virtual void Spawn(Vector3 position_FiredFrom, Vector3 direction_FiredTo)
{

}

public virtual void Update()
{

}
}

class PistolBulletNormal : Bullet
{
private QuadManager quad_Manager;

public PistolBulletNormal(QuadManager quad_Manager)
{
this.damage = 10;
this.quad_Manager = quad_Manager;
this.ray = new CD_Ray(Vector3.Zero, Vector3.Zero);
this.speed = 1.0f;

// IQuad related parameters
this.effect_Type = "effect_Billboarding";
this.height = 2.0f;
this.texture = 0;
this.width = 5.0f;
}

public override void Spawn(Vector3 position_FiredFrom, Vector3 direction_FiredTo)
{
// Update Ray
this.ray.Origin = position_FiredFrom;
this.ray.Direction = direction_FiredTo;

this.isAlive = true;
this.isOcTreeUpdatable = true;

this.position_Current = position_FiredFrom;
this.position_Last = this.position_Current;
this.collision_AABB = new CD_AxisAlignedBoundingBox(this.position_Current, this.width, this.height, this.width);

this.index_Vertices = this.quad_Manager.SpawnQuad(this.position_Current, this);
this.index_Indices = (this.index_Vertices / GameConstants.QUAD_NUMBER_OF_VERTICES) * 6;
}

public override void Update()
{
this.UpdatePosition();
}

public void UpdatePosition()
{
this.isOcTreeUpdatable = true;

this.position_Current += this.ray.Direction * this.speed;
this.position_Last = this.position_Current;

this.quad_Manager.UpdateQuad(this.position_Current, this);
}
}




I will have a Bullet without referring to PistolBulletNormal() or future sub types of Bullets. So will this class work with the abstract method?

Share this post


Link to post
Share on other sites

This topic is 3098 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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