Welcome to Dream.In.Code
Become a C++ Expert!

Join 137,208 C++ Programmers for FREE! Get instant access to thousands of C++ experts, tutorials, code snippets, and more! There are 2,370 people online right now. Registration is fast and FREE... Join Now!




How to copy inherited classes

 
Reply to this topicStart new topic

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

joske
21 May, 2008 - 11:48 AM
Post #1

D.I.C Head
**

Joined: 4 Sep, 2007
Posts: 158



Thanked: 12 times
My Contributions
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):
cpp
/**
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 wink2.gif )
User is offlineProfile CardPM
+Quote Post

joske
RE: How To Copy Inherited Classes
26 Oct, 2008 - 08:57 AM
Post #2

D.I.C Head
**

Joined: 4 Sep, 2007
Posts: 158



Thanked: 12 times
My Contributions
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:
cpp
/**
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;
}

User is offlineProfile CardPM
+Quote Post

Sadaiy
RE: How To Copy Inherited Classes
26 Oct, 2008 - 10:47 AM
Post #3

New D.I.C Head
*

Joined: 3 Oct, 2008
Posts: 38



Thanked: 1 times
My Contributions
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?
User is offlineProfile CardPM
+Quote Post

joske
RE: How To Copy Inherited Classes
26 Oct, 2008 - 01:20 PM
Post #4

D.I.C Head
**

Joined: 4 Sep, 2007
Posts: 158



Thanked: 12 times
My Contributions
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 Oct, 2008 - 01:23 PM
User is offlineProfile CardPM
+Quote Post

baavgai
RE: How To Copy Inherited Classes
26 Oct, 2008 - 05:38 PM
Post #5

Dreaming Coder
Group Icon

Joined: 16 Oct, 2007
Posts: 2,047



Thanked: 106 times
Dream Kudos: 475
Expert In: C, C++, Java, C#, ASP.NET, PHP, Perl, Python, Oracle, SQL Server, MySql, HTML, JavaScript, Lua

My Contributions
QUOTE(Sadaiy @ 26 Oct, 2008 - 02:47 PM) *

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:

cpp

#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.

User is offlineProfile CardPM
+Quote Post

joske
RE: How To Copy Inherited Classes
27 Oct, 2008 - 10:17 AM
Post #6

D.I.C Head
**

Joined: 4 Sep, 2007
Posts: 158



Thanked: 12 times
My Contributions
wow. That's a very nice solution, baavgai! I 'm going to study polymorphism in more detail...
User is offlineProfile CardPM
+Quote Post

joske
RE: How To Copy Inherited Classes
1 Nov, 2008 - 01:06 PM
Post #7

D.I.C Head
**

Joined: 4 Sep, 2007
Posts: 158



Thanked: 12 times
My Contributions
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?

cpp
#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: 1 Nov, 2008 - 01:32 PM
User is offlineProfile CardPM
+Quote Post

joske
RE: How To Copy Inherited Classes
4 Nov, 2008 - 09:07 AM
Post #8

D.I.C Head
**

Joined: 4 Sep, 2007
Posts: 158



Thanked: 12 times
My Contributions
Any ideas?...
User is offlineProfile CardPM
+Quote Post

baavgai
RE: How To Copy Inherited Classes
4 Nov, 2008 - 02:34 PM
Post #9

Dreaming Coder
Group Icon

Joined: 16 Oct, 2007
Posts: 2,047



Thanked: 106 times
Dream Kudos: 475
Expert In: C, C++, Java, C#, ASP.NET, PHP, Perl, Python, Oracle, SQL Server, MySql, HTML, JavaScript, Lua

My Contributions
QUOTE(joske @ 4 Nov, 2008 - 11:07 AM) *

Any ideas?...


I rarely say this, but I'm stumped. Doing research now...

User is offlineProfile CardPM
+Quote Post

baavgai
RE: How To Copy Inherited Classes
4 Nov, 2008 - 03:34 PM
Post #10

Dreaming Coder
Group Icon

Joined: 16 Oct, 2007
Posts: 2,047



Thanked: 106 times
Dream Kudos: 475
Expert In: C, C++, Java, C#, ASP.NET, PHP, Perl, Python, Oracle, SQL Server, MySql, HTML, JavaScript, Lua

My Contributions
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.
cpp

#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;
}



User is offlineProfile CardPM
+Quote Post

joske
RE: How To Copy Inherited Classes
5 Nov, 2008 - 01:16 PM
Post #11

D.I.C Head
**

Joined: 4 Sep, 2007
Posts: 158



Thanked: 12 times
My Contributions
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.
User is offlineProfile CardPM
+Quote Post

Reply to this topicStart new topic
Time is now: 12/4/08 12:43PM

Live C++ Help!

C++ Tutorials

Reference Sheets

C++ Snippets

DIC Chatroom

Bye Bye Ads

Monthly Drawing

Thumb Drive

Top Contributors

Top 10 Kudos This Month