Hi!

How can I call the matching constructor

foreach (Animal d in AnimalBufferList)
{
  this.Add( ....call matching copyconstructor.... (d) );
}
.
.
.
abstract class Animal
{
  public Animal (Animal d)
  {
  }
.
 
 }
}

class Pig: Animal
{
   public Pig(Pig d): base(d)
   {
   }
}

class Cow: Animal
{
    public Cow(Cow d): base(d)
   {
   }
}

I want add a new (a copy of a) cow or pig to my animal list.
this = class AnimalList : List<Animal>
To do this i need to call the correct copy constructor. Is there a way to do this??

Greetings from Austria Annex31B

Recommended Answers

All 8 Replies

You can do it, but I think a better way is to have a Clone() method in the Animal class that the child classes override. Then all you need to do is this:

foreach (Animal d in AnimalBufferList)
{
    Add(d.Clone());
}
commented: Thats what I would do +6

You can do it, but I think a better way is to have a Clone() method...

How can i do it?? I know the Clone() method but i want to know how the constructor version works?
Do you have any code snippets or links where I can see how this would work?

Greetings Annex31B

Little correction to Tom's answer:
To copy objects of reference types, you must close the objects. Not all classes support clone. Types implements ICloneable interface (Implement Clone() interface method) are cloneable. Cloning involves calling the method Clone(), which implemented version of ICloneable interface.

You don't really want to do this in the constructor because then you can't create a new instance of the animal class as you are already constructing one. What you can do is create a static method that returns an instance.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace daniweb
{
  public class Animal : ICloneable
  {
    private string _name;
    public string Name 
    { 
      get { return _name; }
      set { _name = value; }
    }
    private Animal()
    {
    }
    public Animal(string Name)
      : this()
    {
    }
    public static Animal CopyAnimal(Animal Template)
    {
      return Template.Clone();
    }
    #region ICloneable Members
    object ICloneable.Clone()
    {
      return this.MemberwiseClone();
    }
    //Gives us a strongly typed Clone() call
    public Animal Clone()
    {
      return (Animal)((ICloneable)this).Clone();
    }
    #endregion
  }
  //Test class
  public static class AnimalTester
  {
    public static void Test123()
    {
      List<Animal> existingList = new List<Animal>();
      existingList.Add(new Animal("Zebra"));
      existingList.Add(new Animal("Horse"));
      existingList.Add(new Animal("Ox"));
      List<Animal> newList = new List<Animal>();
      //Method 1
      foreach (Animal a in existingList)
      {
        newList.Add(a.Clone());
      }
      //or Method 2
      foreach (Animal a in existingList)
      {
        newList.Add(Animal.CopyAnimal(a));
      }
    }
  }
}
commented: Great. I appreciate this help. +9

You don't really want to do this in the constructor because then you can't create a new instance of the animal class as you are already constructing one. What you can do is create a static method that returns an instance.

Thank you very much for your help! This is a great example.
Which clone/copy method would you prefer? Are both equally well?

My Problem is that my Animal class is abstract (see first post - I'd like to have just cows pigs, zebras,.. but no animals) and i want just one common clone method for all animal species.
Is it possible to use your code for this purpose? Or do I have to override the clone function for each derived animal species?

Greetings from Austria - Annex31B

You can't mark the Clone() call as virtual since you are implementing an interface. What you can do is not implement ICloneable on the base class, or Implement it but mark the implementation as abstract. You could also just implement ICloneable on all of the derived classes. Its just a matter of how you want to do it.

If you want to force all derived classes of "Animal" to use ICloneable then use this. You will want to ignore the strongly typed clone when you start dealing with inheritence like this.

public abstract class Animal : ICloneable
  {
    protected string _name;
    public string Name 
    { 
      get { return _name; }
      set { _name = value; }
    }
    protected Animal()
    {
    }
    public Animal(string Name)
      : this()
    {
      _name = Name;
    }

    #region ICloneable Members
    public abstract object Clone();
    #endregion
  }

  public class Dog : Animal, ICloneable
  {
    private string _breed;
    public string Breed
    {
      get { return _breed; }
      set { _breed = value; }
    }

    public Dog()
      : this(string.Empty, string.Empty)
    {
    }
    public Dog(string Name)
      : this(Name, string.Empty)
    {
    }
    public Dog(string Name, string Breed)
      : base(Name)
    {
      this._breed = Breed;
    }

    public override object Clone()
    {
      return this.MemberwiseClone();
    }

  }

Thanks again!
I have modified your code and got this:

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace AnimalTest
{
    public abstract class Animal :ICloneable
    {
       
        protected string _name;
        protected static int idcounter=1;
        protected int id;
        private Point placeOnField;

        public Animal()
        {
            this.id = idcounter++;
            placeOnField = new Point(this.id * 10, 0);
        }
        public int ID
        {
            get { return id; }
        }

        public string Name
        {
            get { return _name + " " + this.id.ToString(); }
            set { _name = value; }
        }
                
        public Point PlaceOnField
        {
            get { return placeOnField; }
        }
                
        #region ICloneable Member

        abstract public object Clone();

        #endregion 
    }

    public class Pig : Animal
    {
        public Pig(): base()
        {
            this._name = "Pig";
        }        
        public override object Clone() 
        {
            Pig d = new Pig();
            return d;
        }    
    }

    public class Cow : Animal
    {
        public Cow() : base()
        {
            this._name = "Cow";
        }
        
        public override object Clone() 
        {
            Cow d = new Cow();
            return d;
        }
    }
}

I have implemented a Form with two labels and two buttons to test the classes.
The code for the form is here:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace AnimalTest
{
    public partial class Form1 : Form
    {
        List<Animal> liste;
        
        public Form1()
        {
            InitializeComponent();
            liste = new List<Animal>();
            liste.Add(new Cow());
            liste.Add(new Pig());
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Animal f = (Animal) liste[0].Clone();
            this.label1.Text = f.Name;
            this.label2.Text = "Place on Field: ";
            this.label2.Text += f.PlaceOnField.ToString();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Animal f = (Animal)liste[1].Clone();
            this.label1.Text = f.Name;
            this.label2.Text = "Place on Field: ";
            this.label2.Text += f.PlaceOnField.ToString();
        }
    }
}

Is it ok to implement the clone method like I do? Or are there better ways to do this? I think I can not use MemberwiseClone(); because of the Point object. MemberwiseClone would only copy the reference and not the whole object, wouldn't it?

No, Point is a struct and structs are by value not reference. You are safe to use MemberwiseClone() if you don't have any reference type members in the class. It is still easy to use if you have reference type by calling a MemberwiseClone then overwriting your reference types with new instances.

Please mark this thread as solved if you have found a solution to your problem and good luck!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.