Cloning C++ objects

P

pazabo

Hi,

I'm trying to somehow implement polymorphic object cloning (just as it
is in Java), but when I write:

class Object {
public:
virtual Object * clone() const = 0;
// ...
}

class String : public Object {
public:
Object * clone() const { return new String(*this); }
// ...
}

compiler tells me, that I cannot allocate object of class String,
because some methods are "pure". There are some more virtual methods in
Object, but there are all implemented in String. What should I do to
solve this problem?

Paul PAZABO Zaborski
 
M

mlimber

Hi,

I'm trying to somehow implement polymorphic object cloning (just as it
is in Java), but when I write:

class Object {
public:
virtual Object * clone() const = 0;
// ...
}

class String : public Object {
public:
Object * clone() const { return new String(*this); }
// ...
}

compiler tells me, that I cannot allocate object of class String,
because some methods are "pure". There are some more virtual methods in
Object, but there are all implemented in String. What should I do to
solve this problem?

It's likely that you forgot to implement something from Object (or that
you added a pure virtual function in String). Post more code, and we
can probably tell you what the problem is.

Cheers! --M
 
P

pazabo

mlimber said:
It's likely that you forgot to implement something from Object (or that
you added a pure virtual function in String). Post more code, and we
can probably tell you what the problem is.

Cheers! --M

Oh.. I see the problem.. I put "const" after some methods in Object,
but I forgot to do it in String, so compiler considered it as abstract
class.
Anyway, thanks for help :)
 
T

Thomas J. Gritzan

Hi,

I'm trying to somehow implement polymorphic object cloning (just as it
is in Java), but when I write:

class Object {
public:
virtual Object * clone() const = 0;
// ...
}

class String : public Object {
public:
Object * clone() const { return new String(*this); }

I would return a String* here:

String* clone() const { return new String(*this); }

So you can clone a String and get a String without casting.
 
J

JH Trauntvein

Thomas said:
I would return a String* here:

String* clone() const { return new String(*this); }

So you can clone a String and get a String without casting.


Generally, the reason to want to implement a virtual clone() type
method is when you are dealing with polymorphic objects and aren't (or
don't want to be) aware of their exact types. You are generally
dealing with pointers to base classes that define clone() in terms of
themselves. If you already knew the type of the object why wouldn't
you just invoke new with a copy constructor?

Regards,

Jon Trauntvein
 
P

Pete Becker

JH said:
Generally, the reason to want to implement a virtual clone() type
method is when you are dealing with polymorphic objects and aren't (or
don't want to be) aware of their exact types. You are generally
dealing with pointers to base classes that define clone() in terms of
themselves. If you already knew the type of the object why wouldn't
you just invoke new with a copy constructor?

I was going to say the same thing, but in general, it's a little more
complicated. Suppose there's a class derived from String, and you've got
a String*. Then having String::clone() return a String* is handy,
because you can clone the object that the String* points to without
having to cast the returned pointer back from Object*.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 
E

eriwik

method is when you are dealing with polymorphic objects and aren't (or
don't want to be) aware of their exact types. You are generally
dealing with pointers to base classes that define clone() in terms of
themselves. If you already knew the type of the object why wouldn't
you just invoke new with a copy constructor?

Which means that you have something like this:
struct Object {
virtual Object* clone() {
std::cout << "obj\n";
return new Object(*this);
}
};

struct String : public Object {
int a;
virtual String* clone() {
std::cout << "str\n";
return new String(*this);
}
};

int main() {
String* str = new String;
Object* obj1 = str;
Object* obj2 = obj1->clone();
}

As you see if you run the code it's the String::clone() function that
is called, even tough you didn't know that it was a String. If you
didn't use the String::clone() you would not have been able to create a
clone since there is no 'a'-variable in Object, so when calling the
copy-constructor of Object you get an Object and not a String. In other
words, returning a String* does not prevent you from cloning a String
from an Object-pointer, but allows you to clone a String also from a
String-pointer.
 
J

JH Trauntvein

Which means that you have something like this:
struct Object {
virtual Object* clone() {
std::cout << "obj\n";
return new Object(*this);
}
};

struct String : public Object {
int a;
virtual String* clone() {
std::cout << "str\n";
return new String(*this);
}
};

int main() {
String* str = new String;
Object* obj1 = str;
Object* obj2 = obj1->clone();
}

As you see if you run the code it's the String::clone() function that
is called, even tough you didn't know that it was a String. If you
didn't use the String::clone() you would not have been able to create a
clone since there is no 'a'-variable in Object, so when calling the
copy-constructor of Object you get an Object and not a String. In other
words, returning a String* does not prevent you from cloning a String
from an Object-pointer, but allows you to clone a String also from a
String-pointer.

I don't have a reference in front of me but I believe that the return
type is a part of the function signature. If that is the case, the
overloaded version of clone will not act as a virtual method but rather
overshadow the virtual method.

Regards,

Jon Trauntvein
 
P

Pete Becker

JH said:
I don't have a reference in front of me but I believe that the return
type is a part of the function signature. If that is the case, the
overloaded version of clone will not act as a virtual method but rather
overshadow the virtual method.

When the function in the base class returns a pointer or reference to a
class type and the function in the derived class returns a pointer or
reference, respectively, to a type derived from that type, the derived
version still overrides the base version.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 
T

Thomas J. Gritzan

JH said:
I don't have a reference in front of me but I believe that the return
type is a part of the function signature. If that is the case, the
overloaded version of clone will not act as a virtual method but rather
overshadow the virtual method.

You can override a virtual member function and change its return type, but
the new return type must be a derived class. It's called "Covariant Return
Type".

In Java, you can't (don't know if they introduced it in a newer version),
so you have to downcast cloned Objects:

String s = new String("some text");
String cloned = s.clone(); // error, clone() returns Object!

But you already _now_ here, that clone() returns a String, so casting would
be superflous. With Covariant Return Types, you can let the compiler know
that it's a String.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

I don't have a reference in front of me but I believe that the return
type is a part of the function signature. If that is the case, the
overloaded version of clone will not act as a virtual method but rather
overshadow the virtual method.

Small changes of the return type are allowed according to The C++
Programming Language (12.2.6) and an example of using this with a clone-
function can be found in 15.6.2. I'll refrain to quote the relevant
parts since my copy is in Swedish and since the English->Swedish
translation was not the best I'm afraid that any attempt by me to
translate it back will remove whatever correctness is still there.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top