 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Ulrich Eckhardt Guest
|
Posted: Thu Jun 26, 2003 7:14 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
Bob Sabiston wrote:
| Quote: | I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
|
This is a known pattern, it is called 'named copy constructor' and
usually
the virtual memberfunction is called clone().
hth
Uli
--
Questions ?
see C++-FAQ Lite: http://parashift.com/c++-faq-lite/ first !
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Tarjei Knapstad Guest
|
Posted: Thu Jun 26, 2003 7:16 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
Bob Sabiston wrote:
| Quote: | Hello,
Can the following be done in C++?
I have a class "shape", of which there are subclasses "square",
"triangle", "line". Say I have an instance of shape, C, which is one
of these subclasses, only I don't know which. I want to generically
make a new one of those subclasses:
shape *D = new typeof(C);
something like that. Is there something that will work like "typeof"
above? Does that make sense, what I am asking?
I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
|
This is the usuall way of doing this (the virtual function is usually
called Clone() and not New()). It's the most sensible way of creating a
polymorphic copy constructor which is what you're after.
Cheers,
--
Tarjei
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Hansen Guest
|
Posted: Thu Jun 26, 2003 7:18 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
On 26 Jun 2003 01:51:39 -0400, there came a drop of sanity from
[email]bobito (AT) abac (DOT) com[/email] (Bob Sabiston) containing:
| Quote: | Hello,
Can the following be done in C++?
I have a class "shape", of which there are subclasses "square",
"triangle", "line". Say I have an instance of shape, C, which is one
of these subclasses, only I don't know which. I want to generically
make a new one of those subclasses:
shape *D = new typeof(C);
something like that. Is there something that will work like "typeof"
above? Does that make sense, what I am asking?
I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
Thanks!
Bob
[email]bobito (AT) abac (DOT) com[/email]
Generally there is no easy way of avoiding your virtual "New()" |
function...
In fact that idiomi is called a "Virtual Copy Constructor" and for
reference material you can read e.g. "Modern C++ design" by Andrei
Alexandrescu or "Design Patterns" by GoF (Prototype Pattern)...
Easy explenation is that you supply a pure virtual function called
e.g. "Clone" in your interface and then you implement this function in
ALL derived classes, one problem you should be looking for though is
the problem that might arise if you supply a "Rectangule" class which
implements it and then supply a "Box" class derived from "Rectangle"
where you FORGET to implement your "Clone" funciton, this problem is
called "slicing" and is one of the problems with C++ (it's easy to
do).
There are walkarounds this problem, but then you need to do a runtime
check of the size of object beeing copied e.g. ASSERT( sizeof(this) ==
sizeof( xxx_Name_Of_Class) )...
--
"FOOT-AND-MOUTH BELIEVED TO BE FIRST VIRUS
UNABLE TO SPREAD THROUGH MICROSOFT OUTLOOK"
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Graham Menhennitt Guest
|
Posted: Thu Jun 26, 2003 7:35 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
On 26 Jun 2003 01:51:39 -0400, [email]bobito (AT) abac (DOT) com[/email] (Bob Sabiston) wrote:
| Quote: | I have a class "shape", of which there are subclasses "square",
"triangle", "line". Say I have an instance of shape, C, which is one
of these subclasses, only I don't know which. I want to generically
make a new one of those subclasses:
shape *D = new typeof(C);
|
Unfortunately, C++ doesn't provide any mechanism for that.
| Quote: | I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
|
That's exactly what you need to do. By convention, it's called
clone(). It should be virtual (possibly pure virtual) in the base
class and overridden in each subclass.
e.g.
shape*
square::clone() const
{
return new square(*this);
}
Graham
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Nick Wightkin Guest
|
Posted: Thu Jun 26, 2003 7:36 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
Bob Sabiston wrote:
| Quote: | Say I have an instance of shape, C, which is one
of these subclasses, only I don't know which. I want to generically
make a new one of those subclasses:
shape *D = new typeof(C);
|
Hi Bob,
What you want is the Prototype pattern:
shape *D = C->clone();
where,
class shape
{
public:
virtual shape* clone() { return new shape(this); }
}
class square : public shape
{
public:
virtual shape* clone() { return new square(this); }
}
Also, Stroustrup mentions that the return type for square's clone() can
be a
square* instead of a shape*. Not sure if this is supported with all
compilers, though.
-Nick
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Mang Guest
|
Posted: Thu Jun 26, 2003 7:37 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
Bob Sabiston schrieb:
| Quote: | Hello,
Can the following be done in C++?
I have a class "shape", of which there are subclasses "square",
"triangle", "line". Say I have an instance of shape, C, which is one
of these subclasses, only I don't know which. I want to generically
make a new one of those subclasses:
shape *D = new typeof(C);
something like that. Is there something that will work like "typeof"
above? Does that make sense, what I am asking?
I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
|
That's usually exactly the way to go.
This way, you can also use covariant return types.
Why would you like to avoid this solution?
regards,
Thomas
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Rayiner Hashem Guest
|
Posted: Thu Jun 26, 2003 7:38 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
| Quote: | I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
There is a way to do the following, but its supported only as |
extensions to C++, implemented in GCC and Intel C++. Use the 'typeof'
keyword.
Derived* d = new Derived;
Base* b = new typeof(*d);
Now, I have a feeling that this is probably not what you want, since
you have to have an object of type Derived around to begin with. I'm
thinking you want something like:
Base* b = create_object("Derived");
That's entirely possible within C++, but you have to write a function
"create_object" that uses an external mechanism to map strings to
class factories. More information about it, including an
implementation, can be found in Alexanderscu's book, Modern C++
Design.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
nick@byu.edu Guest
|
Posted: Thu Jun 26, 2003 10:26 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
Bob Sabiston wrote:
| Quote: | Hello,
Can the following be done in C++?
|
Yes, but not directly as you wish. You're essentially wanting a
virtual constructor. See C++FAQ-lite 20.6--which has a perfect
example.
new is bound statically at compile time to the type it is allocating,
since there are no virtual constructors, it must know the exact ctor
to call. Thus somewhere in the code you must explicity new that
specific type.
One alternative is to write a single class factory function that
switches on RTTI--but that's usually not preferred if it can be
avoided.
Nick
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Maciej Sobczak Guest
|
Posted: Thu Jun 26, 2003 10:31 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
Hi,
Bob Sabiston wrote:
| Quote: | Hello,
Can the following be done in C++?
I have a class "shape", of which there are subclasses "square",
"triangle", "line". Say I have an instance of shape, C, which is one
of these subclasses, only I don't know which. I want to generically
make a new one of those subclasses:
shape *D = new typeof(C);
something like that. Is there something that will work like "typeof"
above? Does that make sense, what I am asking?
|
Yes, that does make sense. You can even express it in the interface of
your shape class, so that it is more clear to the programmer what he is
doing:
class shape
{
public:
virtual shape * clone() = 0;
virtual void draw() = 0; // etc.
};
class square : public shape
{
public:
virtual square * clone()
{
return new square(*this);
}
virtual void draw() { ... }
};
class triangle : public shape
{
public:
virtual triangle * clone()
{
return new triangle(*this);
}
virtual void draw() { ... }
};
and so on.
The usage is this:
shape *s1 = ...
shape *s2 = s1->clone();
The second line will make a copy of what is currently pointed by s1 and
it will have correct dynamic type. If s1 points to square, you'll get a
new square (in fact, the exact copy of the original); if s1 points to
triangle, you'll get a new triangle (the exact copy of original); and so on.
This idiom is known as virtual copy constructor. It is good to become
familiar with it, since it is usable in variety of situations.
Note that the clone function does not create a default object, because
in hierarchies like yours it is usually difficult to invent the default
square, triangle, etc. Each of them will require different data
(different *amount* of data) to be constructed. This is also the reason
why your idea of using typeof(C) (or whatever) is not a good idea -
there are no default values you could use across the whole hierarchy.
Making a copy of what you already have seems to be a good idea. Of
course, it does not have to be universally good.
Note also that the return type of clone method is not preserved across
the hierarchy. It is OK to return pointers and references to derived
types in derived classes (in this case, they are the same types - you
return trangle * in triangle::clone, square * in square::clone and so
on), but older compilers may stumble over it.
| Quote: | I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
|
Why "avoid"? For the reasons mentioned above (no reasonable defaults in
all classes and probably different number of parameters in each class'
constructor), the virtual method is probably the only way to get a clean
design.
--
Maciej Sobczak
http://www.maciejsobczak.com/
Distributed programming lib for C, C++, Python & Tcl:
http://www.maciejsobczak.com/prog/yami/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Vincent Lascaux Guest
|
Posted: Thu Jun 26, 2003 10:33 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
| Quote: | shape *D = new typeof(C);
something like that. Is there something that will work like "typeof"
above? Does that make sense, what I am asking?
I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
|
Maybe
template<class T>
T* new_from_instance(const T&) { return new T(); }
shape* D = new_from_instance(C);
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jon Sturgeon Guest
|
Posted: Fri Jun 27, 2003 12:33 am Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
On 26 Jun 2003 01:51:39 -0400, [email]bobito (AT) abac (DOT) com[/email] (Bob Sabiston) wrote:
| Quote: | I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
|
This is the well-known "clone" idiom and is the primary reason (AFAIK)
that covariant return types were added to C++. It is the best solution
to your problem, I think.
Jon
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Matthias Hofmann Guest
|
Posted: Fri Jun 27, 2003 12:33 am Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
Stefan Lüer <Stefan.Luer (AT) gmx (DOT) de> schrieb in im Newsbeitrag:
[email]11c47a28.0306260337.334cb535 (AT) posting (DOT) google.com[/email]...
| Quote: | Hi Bob,
You can give each subclass its own new(). But that is of no help, or
do you want to allocate them e.g. from different heaps?
|
What does this have to do with heap allocation? You do have to override
new() in each subclass because each subclass has to decide which type of
object to allocate and return.
Regards,
Matthias
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Siemel Naran Guest
|
Posted: Fri Jun 27, 2003 10:59 am Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
"Maciej Sobczak" <maciej (AT) maciejsobczak (DOT) com> wrote in message
| Quote: | class shape
{
public:
virtual shape * clone() = 0;
virtual void draw() = 0; // etc.
};
|
Good. For memory safety consider returning a smart pointer like an
auto_ptr. You can't use covariant returns though.
class shape
{
public:
typedef std::auto_ptr<shape> auto_ptr;
auto_ptr clone();
virtual void draw() = 0; // etc.
private:
shape * myclone() const = 0; // return new object
};
shape::auto_ptr shape::clone()
{
auto_ptr result(myclone());
assert(typeid(*this) == typeid(*result));
return result;
}
| Quote: | This idiom is known as virtual copy constructor. It is good to become
familiar with it, since it is usable in variety of situations.
|
Definitely!
--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dhruv Guest
|
Posted: Fri Jun 27, 2003 2:02 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
On Thu, 26 Jun 2003 15:36:26 -0400, Dhruv wrote:
| Quote: | On Thu, 26 Jun 2003 01:51:39 -0400, Bob Sabiston wrote:
Hello,
Can the following be done in C++?
I have a class "shape", of which there are subclasses "square",
"triangle", "line". Say I have an instance of shape, C, which is one
of these subclasses, only I don't know which. I want to generically
make a new one of those subclasses:
shape *D = new typeof(C);
something like that. Is there something that will work like "typeof"
above? Does that make sense, what I am asking?
I could make a virtual member function New() and override it in each
subclass, but it seems like there should be a way to avoid that.
I'm not 100% sure, but this *might* just do the trick.
|
Correction made here (printing mistake ).
| Quote: | template
t *create_new (const t& _obj)
{
return new t (_obj); //for copy construction.
//return new t; //for default construction.
}
//in code, you would write:
shape *s = create_new (C);
HTH,
-Dhruv.
|
After having said that, let me warn you that code like this will lead to
major trouble:
int main ()
{
shape *s = new square;
shape *r = new rectangle;
shape *ptr = create_new (s); //disaster;
shape *ptr1 = create_new (*s); //again disaster;
}
-Dhruv.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Nicolas Fleury Guest
|
Posted: Fri Jun 27, 2003 2:08 pm Post subject: Re: can this be done in C++? (a = new B, where B is an insta |
|
|
Nick Wightkin wrote:
| Quote: | Also, Stroustrup mentions that the return type for square's clone() can
be a
square* instead of a shape*. Not sure if this is supported with all
compilers, though.
|
The main compiler not supporting covariant return types is MSVC6. I'm
sure old versions of other compilers might not support it, but I don't
know of any recent release of any compiler not supporting it.
Regards,
Nicolas
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|