473,883 Members | 1,626 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Polymorphic assignment?

I have a base class which has about 150 derived classes. Most of the
derived classes are very similar, and many don't change the base class
at all. All the derived classes have a unique factory method which
returns a new object of the derived type.

The problem I've got is that I now need to polymorphically clone a
derived class object, but I don't want to write a separate 'clone'
method for each of these 150 classes. Instead, I thought I might get
away with just writing one base class clone routine instead, something
like this pseudo-code:

BaseClass BaseClass::clon e() {
BaseClass obj = this->factory(); // line 1
obj = *this; // line 2
return obj;
}

The rationale is that:

(line 1) 'obj' is correctly created as a derived-class object, because
'this->factory()' calls the polymorphic derived-class factory method

(line 2) 'obj = *this' uses the default copy assignment operator in a
given derived class to copy all the derived-class members to 'obj'.

This doesn't work, however, because the compiler doesn't know which
operator= to use in line 2. Basically, line 2 is asking for a
polymorphic assignment.

Is this code fixable? Is there any way to do this without writing 150
clone routines?

Thanks -

Ed
Aug 10 '05 #1
7 3919

Mr. Ed wrote:
I have a base class which has about 150 derived classes. Most of the
derived classes are very similar, and many don't change the base class
at all. All the derived classes have a unique factory method which
returns a new object of the derived type.

The problem I've got is that I now need to polymorphically clone a
derived class object, but I don't want to write a separate 'clone'
method for each of these 150 classes. Instead, I thought I might get
away with just writing one base class clone routine instead, something
like this pseudo-code:

BaseClass BaseClass::clon e() {
BaseClass obj = this->factory(); // line 1
obj = *this; // line 2
return obj;
}
slice. obj is a BaseClass object, it will /always/ be a BaseClass
object; it will /never/ be a derived class object. This initialization
slices off the derived object's behavior when the /copy/ into the obj
is made. Same goes for your return value of clone and factory. You need
to be working with pointers (or references, but they don't apply here)
if you expect polymorphic behavior.

The rationale is that:

(line 1) 'obj' is correctly created as a derived-class object, because
'this->factory()' calls the polymorphic derived-class factory method

(line 2) 'obj = *this' uses the default copy assignment operator in a
given derived class to copy all the derived-class members to 'obj'.

This doesn't work, however, because the compiler doesn't know which
operator= to use in line 2. Basically, line 2 is asking for a
polymorphic assignment.

Is this code fixable? Is there any way to do this without writing 150
clone routines?

Thanks -

Ed


Aug 10 '05 #2
Mr. Ed wrote:
I have a base class which has about 150 derived classes. Most of the
derived classes are very similar, and many don't change the base class
at all.
Why do you have them, then?
All the derived classes have a unique factory method which
returns a new object of the derived type.
What's its signature? Is it a static member function? If not, what
object do you use to call your factory?
The problem I've got is that I now need to polymorphically clone a
derived class object, but I don't want to write a separate 'clone'
method for each of these 150 classes. Instead, I thought I might get
away with just writing one base class clone routine instead, something
like this pseudo-code:

BaseClass BaseClass::clon e() {
BaseClass obj = this->factory(); // line 1
What does 'factory' return, an object? If so, how would you avoid
slicing?
obj = *this; // line 2
At this point 'obj' contains _no_ traces of the derived object 'factory'
may have returned.
return obj;
}

The rationale is that:

(line 1) 'obj' is correctly created as a derived-class object, because
'this->factory()' calls the polymorphic derived-class factory method
But it immediately loses all traces of how it was created when you
initialise the BaseClass object with it.
(line 2) 'obj = *this' uses the default copy assignment operator in a
given derived class to copy all the derived-class members to 'obj'.
In what given derived class? 'obj' has the type BaseClass.
This doesn't work, however, because the compiler doesn't know which
operator= to use in line 2. Basically, line 2 is asking for a
polymorphic assignment.
No, it doesn't. You need 'obj' to be either a reference or a pointer
to invoke anything polymorphically . It can't be a reference because what
would it be a reference of? It could be a pointer to a dynamic object.
Is this code fixable? Is there any way to do this without writing 150
clone routines?


I don't know how your 'factory' method works, but it is most fitting to
have it accept a "prototype" :

BaseClass* factory(BaseCla ss* proto = 0)
{
if (proto)
return new Baseclass(*prot o); // copy-construction
else
return new BaseClass(); // default-construction
}

This way you may need to create a parameterized constructor for each
derived class to accept a reference to base. Whatever it does with it
is only its own business.

Another solution if your 'function' member actually returns a pointer
to a new'ed object. Then polymorphic assignment is possible:

virtual BaseClass& operator=(BaseC lass const other&); // implement
// as you see fit in derived
BaseClass* clone() {
BaseClass* pobj = this->factory();
*pobj = *this; // this will invoke the virtual operator
return pobj;
}

You will have to still implement operator=(BaseC lass const&); in every
derived class (similar to the parameterized constructor I wrote about
earlier).

V
Aug 10 '05 #3
Sorry guys -
BaseClass BaseClass::clon e() {
BaseClass obj = this->factory(); // line 1
obj = *this; // line 2
return obj;
}
I over-simplified my code too much; the factory method returns a smart
pointer to the derived object, and 'obj' is of a smart pointer type. A
better summary would have been:

SP_BaseClass BaseClass::clon e() {
SP_BaseClass obj = this->factory(); // line 1
obj = *this; // line 2
return obj;
}

So, there's no slicing problem in line 1.

On Wed, 10 Aug 2005 13:57:55 -0400, Victor Bazarov
<v.********@com Acast.net> wrote:
Mr. Ed wrote:
I have a base class which has about 150 derived classes. Most of the
derived classes are very similar, and many don't change the base class
at all.


Why do you have them, then?


Long story, but basically to have a heterogeneous tree of these
classes rather than a homogeneous tree.
All the derived classes have a unique factory method which
returns a new object of the derived type.


What's its signature? Is it a static member function? If not, what
object do you use to call your factory?


static member function in each derived class:

class derived_x {
...
static RefType factory(void) { return RefType(new(der ived_x)); }
};

where 'RefType' is a reference-counted smart ptr type.

I'm just working through the rest of your comments. At first sight, it
seems that either I have to use your suggestion of a custom assignment
operator in each derived class, or a custom clone method in each
derived class, which means that I have to add a lot of lines of text
which are basically redundant... :(

Cheers

Ed
Aug 10 '05 #4
Mr. Ed wrote:
[...]
All the derived classes have a unique factory method which
returns a new object of the derived type.
What's its signature? Is it a static member function? If not, what
object do you use to call your factory?

static member function in each derived class:

class derived_x {


class derived_x : public base {
...
static RefType factory(void) { return RefType(new(der ived_x)); }
};
And how the hell can you call the right one (supposedly one in a derived
class) from a base class member function 'clone'? There is no way. You
need a polymorphic factory.
where 'RefType' is a reference-counted smart ptr type.

I'm just working through the rest of your comments. At first sight, it
seems that either I have to use your suggestion of a custom assignment
operator in each derived class, or a custom clone method in each
derived class, which means that I have to add a lot of lines of text
which are basically redundant... :(


Nobody said life was easy... Not it this thread, anyway.

V
Aug 10 '05 #5
On Wed, 10 Aug 2005 14:34:21 -0400, Victor Bazarov
<v.********@com Acast.net> wrote:
Mr. Ed wrote:
[...]
All the derived classes have a unique factory method which
returns a new object of the derived type.

What's its signature? Is it a static member function? If not, what
object do you use to call your factory?

static member function in each derived class:

class derived_x {


class derived_x : public base {
...
static RefType factory(void) { return RefType(new(der ived_x)); }
};


And how the hell can you call the right one (supposedly one in a derived
class) from a base class member function 'clone'? There is no way. You
need a polymorphic factory.


It is polymorphic. The base class has a virtual factory method; the
derived classes over-ride it with a static member. I'm assuming that
in line 1:

BaseClass BaseClass::clon e() {
BaseClass obj = this->factory(); // line 1
...
}

the correct derived class is called. Are you saying that this is
wrong?

Cheers

Ed
Aug 10 '05 #6
Mr. Ed wrote:
On Wed, 10 Aug 2005 14:34:21 -0400, Victor Bazarov
<v.********@com Acast.net> wrote:

Mr. Ed wrote:
[...]

>All the derived classes have a unique factory method which
>returns a new object of the derived type.

What's its signature? Is it a static member function? If not, what
object do you use to call your factory?
static member function in each derived class:

class derived_x {
class derived_x : public base {

...
static RefType factory(void) { return RefType(new(der ived_x)); }
};


And how the hell can you call the right one (supposedly one in a derived
class) from a base class member function 'clone'? There is no way. You
need a polymorphic factory.

It is polymorphic. The base class has a virtual factory method; the
derived classes over-ride it with a static member.


WHAT???
I'm assuming that
in line 1:

BaseClass BaseClass::clon e() {
BaseClass obj = this->factory(); // line 1
...
}

the correct derived class is called. Are you saying that this is
wrong?


Uh... Wrong? How should I break it to you?... You simply cannot
override a virtual member function with a static one. Otherwise, no,
it's not wrong.

V
Aug 10 '05 #7

Mr. Ed wrote:
I have a base class which has about 150 derived classes. Most of the
derived classes are very similar, and many don't change the base class
at all. All the derived classes have a unique factory method which
returns a new object of the derived type.

The problem I've got is that I now need to polymorphically clone a
derived class object, but I don't want to write a separate 'clone'
method for each of these 150 classes. Instead, I thought I might get
away with just writing one base class clone routine instead, something
like this pseudo-code:

BaseClass BaseClass::clon e() {
BaseClass obj = this->factory(); // line 1
obj = *this; // line 2
return obj;
}

The rationale is that:

(line 1) 'obj' is correctly created as a derived-class object, because
'this->factory()' calls the polymorphic derived-class factory method

(line 2) 'obj = *this' uses the default copy assignment operator in a
given derived class to copy all the derived-class members to 'obj'.

This doesn't work, however, because the compiler doesn't know which
operator= to use in line 2. Basically, line 2 is asking for a
polymorphic assignment.

Is this code fixable? Is there any way to do this without writing 150
clone routines?


I recommend using the following clone smart pointer class:
http://code.axter.com/clone_ptr.h

The above clone smart pointer, does not need a clone method. It can
correctly duplicate the correct derived copy of itself through the
assignment operator.
Example code:
void CopyCorrectDeri vedTypeDemo()
{
std::vector<clo ne_ptr<BaseClas s> > vBaseClass;
//Setup data using base and derived type classes
vBaseClass.push _back(new BaseClass( "3" ));
vBaseClass.push _back(new Derived_B( "2" ));
vBaseClass.push _back(new BaseClass( "1" ));
vBaseClass.push _back(new Derived_A( "5" ));
vBaseClass.push _back(new BaseClass( "4" ));

//Copy contents from one container to another
std::vector<clo ne_ptr<BaseClas s> > vBaseClass_Copy (vBaseClass.beg in(),
vBaseClass.end( ));

//Display results
for (int i = 0;i < vBaseClass_Copy .size();++i)
{
vBaseClass_Copy[i]->WhoAmI();
}
In above example code, the vBaseClass_Copy container gets the correct
dervied copy from the vBaseClass container.
This smart pointer does not share the pointer, and instead has strict
pointer ownership.

Aug 11 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
1498
by: Dave | last post by:
What is the expected output of this program and why??? #include <iostream> using namespace std; class base {
20
2240
by: verec | last post by:
One problem I've come accross in designing a specific version of auto_ptr is that I have to disntiguish between "polymorphic" arguments and "plain" ones, because the template has to, internally, cast to void *. Specifically, template <typename T> void f(T * t) { void * p = dynamic_cast<void *>(t) ; } will not compile if T isn't of a class that has somewhere at least
1
2266
by: verec | last post by:
Last week I asked here how I could detect that a T was polymorphic, and received very thoughtful and useful replies that I used straight away. Thanks to all who answered. This week, it turns out that detecting whether T is polymorphic clashes with a new requirement, that T be allowed to not be complete. Last week, this code used to compile:
7
2086
by: James Fortune | last post by:
In response to different users or situations (data context) I transform the appearance and characteristics of Access Forms through code. This seems to fit in with the idea of polymorphism. Do people consider Access Forms to be Polymorphic? James A. Fortune
10
2610
by: Christian Christmann | last post by:
Hi, how do I define an assignment operator which is supposed to copy all member attributes of one object to another where both objects are given as pointers? Example: CLASS_A *source = new CLASS_A; ....
11
2415
by: anongroupaccount | last post by:
What measures should be taken to avoid this sort of thing? class Base { }; class Derived1 : public Base { private: int i, j, k;
6
1523
by: toton | last post by:
Hi, I am inheriting a vector<Pointclass as a PointVector non-polymorphically, to add several additional functionalities to it. I know the dangers of inheriting a container class, as it doesn't have a virtual destructor from a previous post by me, and thus it is designed as a safe way. As the PointVector is non polymorphic (and its runtime typeid also shows the same), can I assume it is as efficient as a typedef to vector<Point? i.e no...
12
1932
by: siddhu | last post by:
Dear experts, #include <stdio.h> class Base { }; class Der1:public Base {
2
1467
by: Daniel Pitts | last post by:
I'm trying decide on the best way to structure the memory management in my program. I have a class (lets call it World), which contains a collection of Entity objects. Entity in turn, contains a pointer a Shape object. Shape is a pure virtual class. Now, I'm not sure who should "own" the allocation and deallocation of
0
9793
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
11151
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10419
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7974
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
7134
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5804
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5996
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4619
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
3237
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.