How to copy inherited classes

How to copy objects which are inherited from the same base class?

Page 1 of 1

10 Replies - 2675 Views - Last Post: 05 November 2008 - 02:16 PM Rate Topic: -----

#1 joske  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 43
  • View blog
  • Posts: 297
  • Joined: 04-September 07

How to copy inherited classes

Posted 21 May 2008 - 12:48 PM

I have a set of classes which are all inherited from one class.
Now I would like to copy objects of the inherited classes from one to another, without having to de-cast them.

Is there a way to do that?

The following example shows what I would like to do (but what doesn't work this way):
/**
test how to copy inheritated objects
*/ 

#include <cstdlib>
#include <cstdio>

class Fruit
{
public:
    virtual const char* get_name() 
    {
        return "(nothing)";
    }
};

class Apple: public Fruit
{
public:
    const char* get_name() 
    {
        return "Apple";
    }
};

class Orange: public Fruit
{
public:
    const char* get_name()
    {
        return "Orange";
    }
};

int main(int argc, char *argv[])
{
    printf("Test inheritation \n");

    Fruit *myfruit1 = new Apple();
    Fruit *myfruit2 = new Orange();
    Fruit *myfruit3 = new Apple();

    printf("myfruit1 = %s \n", myfruit1->get_name());       // prints "Apple"
    printf("myfruit2 = %s \n", myfruit2->get_name());       // prints "Orange"
    printf("myfruit3 = %s \n", myfruit3->get_name());       // prints "Apple"

    // The following does not work
    printf("Now change myfruit3 from Apple to Orange... \n");
    *myfruit3 = *myfruit2;
    printf("myfruit3 = %s \n", myfruit3->get_name());       // prints "Apple" but should print "Orange"

    delete myfruit1;
    delete myfruit2;
    delete myfruit3;

    system("pause");
    return EXIT_SUCCESS;
}


(o, and don't bother about the physical interpretation of the example - it is just an example ;) )

Is This A Good Question/Topic? 0
  • +

Replies To: How to copy inherited classes

#2 joske  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 43
  • View blog
  • Posts: 297
  • Joined: 04-September 07

Re: How to copy inherited classes

Posted 26 October 2008 - 09:57 AM

I finally found a solution. You can create an assignment operator in the main class Fruit, and in there specify what to do if the types do not match: then, the object is deleted, and a new one is created with the right type and contents. (I checked for memory leakages).

here a demo:
/**
Copy inheritated objects

*/ 

#include <cstdlib>
#include <cstdio>
#include <typeinfo>


#define PAUSE {printf("Press Enter to continue...\n"); fflush(stdin); getchar(); fflush(stdin);}


class Fruit;
class Apple;
class Orange;

class Fruit
{
public:
  Fruit()
  {
    setWeight(0.0);
  }
  Fruit(float weight)
  {
    setWeight(weight);
  }

  Fruit operator= (const Fruit &a);

  virtual const char* getName() const
  {
    return "(nothing)";
  }

  float getWeight() const
  {
    return weight_;
  }
  void setWeight(float weight)
  {
    weight_ = weight;
  }
private:
  float weight_;
};


class Apple: public Fruit
{
public:
  Apple(float weight)
  {
    setWeight(weight);
  }

  const char* getName() const
  {
    return "Apple";
  }
};


class Orange: public Fruit
{
public:
  Orange(float weight)
  {
    setWeight(weight);
  }

  const char* getName() const
  {
    return "Orange";
  }
};



Fruit Fruit::operator= (const Fruit &a)
{
  Fruit* me = this;

  if (this != &a)
  {
    if (typeid(a) == typeid(Apple))
    {
      // change type to Apple
      if (typeid(a) == typeid(me))
      {
        // me and a are same type. Copy the contents
        const Apple* a_cast = static_cast<const Apple*>(&a);
        Apple* me_cast = static_cast<const Apple*>(me);
        *me_cast = *a_cast;
      }
      else
      {
        // me is not the same type as a.
        // Delete me and create a new instance
        delete me;
        const Apple* a_cast = static_cast<const Apple*>(&a);
        me = new Apple(*a_cast);
      }
    }
    else if (typeid(a) == typeid(Orange))
    {
      // change type to Orange
      if (typeid(a) == typeid(me))
      {
        // me and a are same type. Copy the contents
        const Orange* a_cast = static_cast<const Orange*>(&a);
        Orange* me_cast = static_cast<const Orange*>(me);
        *me_cast = *a_cast;
      }
      else
      {
        // me is not the same type as a.
        // Delete me and create a new instance
        delete me;
        const Orange* a_cast = static_cast<const Orange*>(&a);
        me = new Orange(*a_cast);
      }
    }
    else
    {
      printf("Error: can not change type %s to type %s\n", getName(), a.getName());
    }
  }
  return *me;
}


int main(int argc, char *argv[])
{
  printf("Test inheritation \n");

  Fruit *myfruit1 = new Apple(2.5);
  Fruit *myfruit2 = new Orange(1.1);
  Fruit *myfruit3 = new Apple(3.3);

  printf("myfruit1 = %s, weight = %.1f \n", myfruit1->getName(), myfruit1->getWeight());       // prints "Apple, 2.5"
  printf("myfruit2 = %s, weight = %.1f \n", myfruit2->getName(), myfruit2->getWeight());       // prints "Orange, 1.1"
  printf("myfruit3 = %s, weight = %.1f \n", myfruit3->getName(), myfruit3->getWeight());       // prints "Apple, 3.3"

  printf("Now change myfruit3 from Apple to Orange... \n");
  *myfruit3 = *myfruit2;
  printf("myfruit3 = %s, weight = %.1f \n", myfruit3->getName(), myfruit3->getWeight());       // prints "Orange, 1.1"

  delete myfruit1;
  delete myfruit2;
  delete myfruit3;

  PAUSE;
  return EXIT_SUCCESS;
}


Was This Post Helpful? 0
  • +
  • -

#3 Sadaiy  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 107
  • Joined: 03-October 08

Re: How to copy inherited classes

Posted 26 October 2008 - 11:47 AM

Does this work?

i thought you would have to :

Apple *myFruit = new Apple;
Orange *myFruit = new Orange;
Bananna *myFruit = new Apple;

not:

Fruit *myFruit = new Apple;
Fruit *myFruit = new Orange;

etc etc.

Why do you use Fruit (base class) instead of using the inherited class to create the object ? I don't understand that part, can you explain it to me?
Was This Post Helpful? 0
  • +
  • -

#4 joske  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 43
  • View blog
  • Posts: 297
  • Joined: 04-September 07

Re: How to copy inherited classes

Posted 26 October 2008 - 02:20 PM

Well, it is for a math program I'm working on. I have different types of math objects: normal values, strings, and matrices. Some functions may return different types of objects depending on the parameters of the function. So, I need to return one base class (Fruit in the example) that can contain all types of math objects (Apple and Orange in the example).

Furthermore, I tested the fastest way to handle type casting. You can of course declare different functions for all types of parameters, but you can also do the typecasting by hand. And that works faster in my case. So I think I will make one declaration for each function and pass the base class as parameter, and inside the functions use typeid and typecasting to handle the different types of values (value, string, matrix). This makes it also easy to handle errors for functions that can not deal with all types of math values (for example functions that can only accept a string as input value).

In short: I want to use the base class as input of functions, and want to get back the base class as result.

I'm still looking around for the nicest way to solve this problem, so any idea is welcome.

This post has been edited by joske: 26 October 2008 - 02:23 PM

Was This Post Helpful? 0
  • +
  • -

#5 baavgai  Icon User is online

  • Dreaming Coder
  • member icon

Reputation: 5826
  • View blog
  • Posts: 12,681
  • Joined: 16-October 07

Re: How to copy inherited classes

Posted 26 October 2008 - 06:38 PM

View PostSadaiy, on 26 Oct, 2008 - 02:47 PM, said:

Does this work?

Why do you use Fruit (base class) instead of using the inherited class to create the object ? I don't understand that part, can you explain it to me?


This is an example of "polymorphism", a fundamental property of OOP. Being able to treat various classes as a base class has many advantages. e.g. you could have a vector or array of BaseObject, but in fact contain any child of that object within the structure.

For the example given, I don't like the "typeid ==" business in the base class. It's not really object oriented in design. What if I decide to add a new fruit? I have to tell the base. It's difficult to extend and therefor maintain.

Better the write the base in such a way that I can extend it without needing to tell it. Here's an example of how I might do it:

#include <iostream>

using namespace std;

class Fruit {
protected:
	float weight;
	virtual Fruit *copy() const { return new Fruit(*this); }
public:
	Fruit(float weight) { setWeight(weight); }
	Fruit(const Fruit &other) { setWeight(other.weight); }
	virtual Fruit operator = (const Fruit &other) {
		 cout << endl << "Fruit operator =" << endl;
		 if (this != &other) { 
			  Fruit* me = this;
			  delete me;
			  me = other.copy();
		 }
		 return *this;
	}
	virtual const char* getName() const { return "(nothing)"; };
	float getWeight() const { return weight; }
	void setWeight(float weight) { this->weight = weight; }
	friend ostream &operator<<(ostream &out, Fruit &obj) {
		  out << obj.getName() << ", weight = " << obj.getWeight();
		  return out;
	 }
};


class Apple: public Fruit {
protected:
	virtual Fruit *copy() const {  return new Apple(*this); }
public:
	Apple(const Fruit &other) : Fruit(other) {};
	const char* getName() const { return "Apple"; }
};


class Orange: public Fruit {
protected:
	virtual Fruit *copy() const {  return new Orange(*this); }
public:
	Orange(const Fruit &other) : Fruit(other) {};
	const char* getName() const { return "Orange"; }
};


int main(int argc, char *argv[]) {
	Fruit *myfruit1 = new Apple(2.5);
	Fruit *myfruit2 = new Orange(1.1);
	Fruit *myfruit3 = new Apple(3.3);

	cout << "myfruit1 = " << *myfruit1 << endl;
	cout << "myfruit2 = " << *myfruit2 << endl;
	cout << "myfruit3 = " << *myfruit3 << endl;

	cout << "Now change myfruit3 from Apple to Orange..."<< endl;
	*myfruit3 = *myfruit2;
	cout << "myfruit3 = " << *myfruit3 << endl;

	delete myfruit1;
	delete myfruit2;
	delete myfruit3;
	return 0;
}



Hope this helps.
Was This Post Helpful? 0
  • +
  • -

#6 joske  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 43
  • View blog
  • Posts: 297
  • Joined: 04-September 07

Re: How to copy inherited classes

Posted 27 October 2008 - 11:17 AM

wow. That's a very nice solution, baavgai! I 'm going to study polymorphism in more detail...
Was This Post Helpful? 0
  • +
  • -

#7 joske  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 43
  • View blog
  • Posts: 297
  • Joined: 04-September 07

Re: How to copy inherited classes

Posted 01 November 2008 - 02:06 PM

baavgai,

I extended your example a little bit with class specific data. In the class Apple I added a private double value. Now the program crashes when compiling: "segmentation fault". Any ideas how to solve that?

#include <iostream>

using namespace std;

class Fruit {
protected:
	float weight;
	virtual Fruit *copy() const { return new Fruit(*this); }
public:
	Fruit(float weight) { setWeight(weight); }
	Fruit(const Fruit &other) { setWeight(other.weight); }
	virtual Fruit operator = (const Fruit &other) {
		 cout << endl << "Fruit operator =" << endl;
		 if (this != &other) {
			  Fruit* me = this;
			  delete me;
			  me = other.copy();
		 }
		 return *this;
	}
	virtual const char* getName() const { return "(nothing)"; };
	float getWeight() const { return weight; }
	void setWeight(float weight) { this->weight = weight; }
	friend ostream &operator<<(ostream &out, Fruit &obj) {
		  out << obj.getName() << ", weight = " << obj.getWeight();
		  return out;
	 }
};


class Apple: public Fruit {
protected:
	virtual Fruit *copy() const {  return new Apple(*this); }
public:
	Apple(const Fruit &other) : Fruit(other) {};
	const char* getName() const { return "Apple"; }
private:
  double appleSpecificValue_;   // Adding this causes the program to crash in Windows
};


class Orange: public Fruit {
protected:
	virtual Fruit *copy() const {  return new Orange(*this); }
public:
	Orange(const Fruit &other) : Fruit(other) {};
	const char* getName() const { return "Orange"; }
};


int main(int argc, char *argv[]) {
	Fruit *myfruit1 = new Apple(2.5);
	Fruit *myfruit2 = new Orange(1.1);
	Fruit *myfruit3 = new Apple(3.3);

	cout << "myfruit1 = " << *myfruit1 << endl;
	cout << "myfruit2 = " << *myfruit2 << endl;
	cout << "myfruit3 = " << *myfruit3 << endl;

	cout << "Now change myfruit3 from Apple to Orange..."<< endl;
	*myfruit3 = *myfruit2;
	cout << "myfruit3 = " << *myfruit3 << endl;

	delete myfruit1;
	delete myfruit2;
	delete myfruit3;
	return 0;
}


This post has been edited by joske: 01 November 2008 - 02:32 PM

Was This Post Helpful? 0
  • +
  • -

#8 joske  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 43
  • View blog
  • Posts: 297
  • Joined: 04-September 07

Re: How to copy inherited classes

Posted 04 November 2008 - 10:07 AM

Any ideas?...
Was This Post Helpful? 0
  • +
  • -

#9 baavgai  Icon User is online

  • Dreaming Coder
  • member icon

Reputation: 5826
  • View blog
  • Posts: 12,681
  • Joined: 16-October 07

Re: How to copy inherited classes

Posted 04 November 2008 - 03:34 PM

View Postjoske, on 4 Nov, 2008 - 11:07 AM, said:

Any ideas?...


I rarely say this, but I'm stumped. Doing research now...
Was This Post Helpful? 0
  • +
  • -

#10 baavgai  Icon User is online

  • Dreaming Coder
  • member icon

Reputation: 5826
  • View blog
  • Posts: 12,681
  • Joined: 16-October 07

Re: How to copy inherited classes

Posted 04 November 2008 - 04:34 PM

Honestly, I'd don't know how a process that seems to be working perfectly well can be corrupted by simply adding an attribute to a class.

That said, I was never trully comfortable with that process. An object simply shouldn't be allowed to change itself in that manner; I was surprised it worked in the first place. I'm a language generalist, rather than a specialist. Perhaps a true C++ devotee might have some thought.

Here's another approach, real close to the first one. Less slick, but I think more legible.
#include <iostream>

using namespace std;

class Fruit {
protected:
	float weight;
public:
	Fruit(float weight) { setWeight(weight); }
	Fruit(const Fruit &other) { setWeight(other.weight); }
	virtual const char* getName() const { return "(nothing)"; };
	float getWeight() const { return weight; }
	void setWeight(float weight) { this->weight = weight; }
	friend ostream &operator<<(ostream &out, Fruit &obj) {
		out << obj.getName() << ", weight = " << obj.getWeight();
		return out;
	 }
	virtual Fruit *copy() const { return new Fruit(*this); }
};


class Apple: public Fruit {
private:
	 double appleSpecificValue_;   // Adding this causes the program to crash in Windows
public:
	Apple(float weight, double appleSpecificValue_) : Fruit(weight) { this->appleSpecificValue_ = appleSpecificValue_; };
	Apple(const Apple &other) : Fruit(other) { this->appleSpecificValue_ = appleSpecificValue_; };
	Apple(const Fruit &other) : Fruit(other) {};
	const char* getName() const { return "Apple"; }
	virtual Fruit *copy() const {  return new Apple(*this); }
};


class Orange: public Fruit {
public:
	Orange(const Fruit &other) : Fruit(other) {};
	const char* getName() const { return "Orange"; }
	virtual Fruit *copy() const {  return new Orange(*this); }
};


int main(int argc, char *argv[]) {
	Fruit *myfruit1 = new Apple(2.5);
	Fruit *myfruit2 = new Orange(1.1);
	Fruit *myfruit3 = new Apple(3.3);

	cout << "myfruit1 = " << *myfruit1 << endl;
	cout << "myfruit2 = " << *myfruit2 << endl;
	cout << "myfruit3 = " << *myfruit3 << endl;

	cout << "Now change myfruit3 from Apple to Orange..."<< endl;
	myfruit3 = myfruit2->copy();
	cout << "myfruit3 = " << *myfruit3 << endl;

	delete myfruit1;
	delete myfruit2;
	delete myfruit3;
	return 0;
}


Was This Post Helpful? 0
  • +
  • -

#11 joske  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 43
  • View blog
  • Posts: 297
  • Joined: 04-September 07

Re: How to copy inherited classes

Posted 05 November 2008 - 02:16 PM

Thanks. Yes, that is a possibility. Though it is pretty dangerous as you can easily get memory leakages this way (if I'm correct). Before doing myfruit3 = myfruit2->copy(); you should delete the pointer myfruit3 to prevent a memory leakage.

So, probably my whole approach is not very handy.

Does anybody have an idea for an other approach? The problem is: I want to create a math program which deals with values, complex values, strings, and matrices. And I want to be able to store these objects for example in variables in a workspace. That was the reason I thought about one main "math object", from which all different objects (value, string, matrix) are inherited, making it easy to store any type anywhere.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1