Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Clone an object with an abstract base class

134 views
Skip to first unread message

Urs Thuermann

unread,
Oct 11, 2014, 6:09:11 PM10/11/14
to
I want to clone an object through a pointer to its abstract base
class. Say I have the following classes

class B {
virtual void foo() = 0; // abstract base class
};
class D1 : public B {
virtual void foo();
};
class D2 : public B {
virtual void foo();
};

Then I can clone objects when I know the subclass of B

void f1(D1 *d1, D2 *d2) {
B *b1 = new D1(*d1);
B *b2 = new D2(*d2);
}

but not if I only have a pointer to the abstract base class

void f2(B *b) {
B *b1 = new B(*b); // error: cannot create a B
}

With GCC and -std=c++11 I can write

void f2(B *b) {
B *b1 = new auto(*b);
}

Is this the correct and preferred way in C++11?

In C++98 the only way I found is to add a pure virtual function

B *B::clone() const

and

B *D1::close() const { return new D1(*this); }
B *D2::close() const { return new D2(*this); }

and then call b->clone() instead of the new operator.

Is there a way to do this in C++98 without the need to add a new
function like clone() in each derived class?

urs

JiiPee

unread,
Oct 11, 2014, 7:07:11 PM10/11/14
to
On 11/10/2014 22:46, Urs Thuermann wrote:
> I want to clone an object through a pointer to its abstract base
> class. Say I have the following classes
>
> class B {
> virtual void foo() = 0; // abstract base class
> };
> class D1 : public B {
> virtual void foo();
> };
> class D2 : public B {
> virtual void foo();
> };
>
> Then I can clone objects when I know the subclass of B
>
> void f1(D1 *d1, D2 *d2) {
> B *b1 = new D1(*d1);
> B *b2 = new D2(*d2);
> }
>
> but not if I only have a pointer to the abstract base class
>
> void f2(B *b) {
> B *b1 = new B(*b); // error: cannot create a B
> }


>
> With GCC and -std=c++11 I can write
>
> void f2(B *b) {
> B *b1 = new auto(*b);
> }

with my GCC and c++11 on does not work:
error: cannot allocate an object of abstract type 'B'

JiiPee

unread,
Oct 11, 2014, 7:26:28 PM10/11/14
to
On 11/10/2014 22:46, Urs Thuermann wrote:
How about checking the type of the *b object first and creating that
type of object:

void f2(B *b) {
B *b1 = nullptr;
if( typeid(*b).name() == typeid(D1).name() )
b1 = new D1(*b1); // *b is type D1
else if( typeid(*b).name() == typeid(D2).name() )
b1 = new D2(*b1); // *b is type D2
}

and maybe also *b1 must be converted to its type like:
new D1( *((D1*)b1) )
?

Thats how I would do it propably :). At least a go-around. But there
might be better ways.

JiiPee

unread,
Oct 11, 2014, 7:55:52 PM10/11/14
to
On 12/10/2014 00:26, JiiPee wrote:
>
> How about checking the type of the *b object first and creating that
> type of object:
>
> void f2(B *b) {
> B *b1 = nullptr;
> if( typeid(*b).name() == typeid(D1).name() )
> b1 = new D1(*b1); // *b is type D1
> else if( typeid(*b).name() == typeid(D2).name() )
> b1 = new D2(*b1); // *b is type D2
> }
>
> and maybe also *b1 must be converted to its type like:
> new D1( *((D1*)b1) )
> ?
>

this is better and compiles:

void f2(B *b) {
B *b1 = nullptr;
if( typeid(*b).name() == typeid(D1).name() )
b1 = new D1(*(reinterpret_cast<D1*>(b1)));
else if( typeid(*b).name() == typeid(D2).name() )
b1 = new D2(*(reinterpret_cast<D2*>(b1)));
}

Mr Flibble

unread,
Oct 11, 2014, 8:18:41 PM10/11/14
to
You should use static_cast not reinterpret_cast when casting from base
to derived.

/Flibble

Mr Flibble

unread,
Oct 11, 2014, 8:20:24 PM10/11/14
to
Of course your solution doesn't scale: what if b points to an object
derived from D1?

Much better solution is to have a pure virtual clone() method.

/Flibble

JiiPee

unread,
Oct 11, 2014, 8:22:58 PM10/11/14
to
On 12/10/2014 01:18, Mr Flibble wrote:
yes, correct. And I guess from derived to base as well

JiiPee

unread,
Oct 11, 2014, 8:27:31 PM10/11/14
to
Then that new derived class should be added, so one if- more. But this
is also the case if more classes are derived from from B; they all need
to have their own if-block.

Ian Collins

unread,
Oct 11, 2014, 8:31:25 PM10/11/14
to
Why is that better than a clone method?

--
Ian Collins

JiiPee

unread,
Oct 11, 2014, 8:32:15 PM10/11/14
to
I did not say its better. :)

JiiPee

unread,
Oct 11, 2014, 8:37:43 PM10/11/14
to
On 12/10/2014 01:31, Ian Collins wrote:
he asked: "Is there a way to do this in C++98 without the need to add a
new function like clone() in each derived class?"

I guess I was just trying answer his this question: in my solution there
is no need to create clone().
But yes, the clone might be better.

JiiPee

unread,
Oct 11, 2014, 8:52:04 PM10/11/14
to
On 12/10/2014 01:31, Ian Collins wrote:
>
> Why is that better than a clone method?
>

Was thinking if there are any reasons. There is one reason: Was it
Sutter who said that class should have as less funtions as possible. So
doing this globally would reduce the number of functions in classes. He
also said that its better to do things in global functions instead of
having a member function. So my solution would serve that aim: its a
global function instead of having one more member function.

But yes the downside here is that it is depending on the classes so this
"advantage" might not be sufficient to chose it as a solution.

JiiPee

unread,
Oct 11, 2014, 8:58:56 PM10/11/14
to
lets think about a situation for example it being a string class. So then:

class string
{
public:
B* clone() { ... }
...
other string functions
}

And documentation saying: "clone: makes a clone of the string-object and
returns its base class pointer B*".
The user of string class might be confused: Why on earth we need that
clone there - I am never using it? :).

So i guess it also depends on the situation whether clone or global
solution is better. So we would not have this problem if cloning is done
in a global function.

Mr Flibble

unread,
Oct 11, 2014, 9:02:21 PM10/11/14
to
On 12/10/2014 01:51, JiiPee wrote:
I think you are talking about decreasing encapsulation by increasing the
number of public member functions; really this is only do once for the
base class; overriding virtual functions doesn't decrease encapsulation IMO.

/Flibble


JiiPee

unread,
Oct 11, 2014, 9:08:43 PM10/11/14
to
It would add one member function more to a class. Obviously the problem
is only if its public.

Mr Flibble

unread,
Oct 11, 2014, 9:15:32 PM10/11/14
to
Virtual functions are virtual because they are *meant* to be derived
from otherwise they would not be virtual therefore unless they are
marked as final overriding them doesn't increase complexity of the OO
design.

/Flibble

JiiPee

unread,
Oct 11, 2014, 9:19:55 PM10/11/14
to
I do not mean it adds. In his example there would be *totally* 1 member
function added to increase complexity, not 3.

Paavo Helde

unread,
Oct 12, 2014, 2:44:45 AM10/12/14
to
JiiPee <n...@notvalid.com> wrote in news:Jgk_v.667156$an2.6...@fx09.am4:

> On 12/10/2014 01:31, Ian Collins wrote:
>>
>> Why is that better than a clone method?
>>
>
> Was thinking if there are any reasons. There is one reason: Was it
> Sutter who said that class should have as less funtions as possible. So
> doing this globally would reduce the number of functions in classes.

I agree that class public interface should be as minimal as possible - but
not smaller! This example of unscalable mess with typeid checking is
exactly the reason why virtual functions were invented in the first place.

Cheers
Paavo

Paavo Helde

unread,
Oct 12, 2014, 3:57:59 AM10/12/14
to
Urs Thuermann <u...@isnogud.escape.de> wrote in
news:ygfppdy...@tehran.isnogud.escape.de:

> I want to clone an object through a pointer to its abstract base
> class.
> With GCC and -std=c++11 I can write
>
> void f2(B *b) {
> B *b1 = new auto(*b);
> }
>
> Is this the correct and preferred way in C++11?

To work as expected, one needs to have dynamic type lookup at runtime
here, but 'auto' is a compile-time concept, so I don't think it helps
here.

Moreover, it should know all possible run-time types of B-derived classes
at compile time, but this is in principle impossible (as one can add new
dynamic libraries with new classes at runtime).


> In C++98 the only way I found is to add a pure virtual function
>
> B *B::clone() const
>
> and
>
> B *D1::close() const { return new D1(*this); }
> B *D2::close() const { return new D2(*this); }
>
> and then call b->clone() instead of the new operator.
>
> Is there a way to do this in C++98 without the need to add a new
> function like clone() in each derived class?

Yes, that's the way to do it. 1 extra line per class is not so much.

Cheers
Paavo

JiiPee

unread,
Oct 12, 2014, 5:04:17 AM10/12/14
to
but if for example std::string public interface had a function called:
B* clone();
which nobody really uses other than some code internally, then isn't it
bad from the users point of view seeing this kind of clone function
which they never need?

But surely there is a way to hide the clone, like being protected, then
this would not be a problem.

JiiPee

unread,
Oct 12, 2014, 5:06:20 AM10/12/14
to
On 12/10/2014 07:44, Paavo Helde wrote:
I would not like to see B* clone() being a public member of a
std::string class. But if its a private member then it would be ok. The
functions calling it can be friends so they can get access to private
clone().

Paavo Helde

unread,
Oct 12, 2014, 10:02:48 AM10/12/14
to
JiiPee <n...@notvalid.com> wrote in news:6wr_v.485831$KL.2...@fx19.am4:
>
> I would not like to see B* clone() being a public member of a
> std::string class. But if its a private member then it would be ok.
> The functions calling it can be friends so they can get access to
> private clone().

std::string is not a polymorphic class so it does not need a clone
function. In general, fundamental value classes (like std::string) cannot
have any virtual methods as this might hinder their usability (think an
array of million strings, this would be a million wasted vtable pointers).

Cheers
P

Luca Risolia

unread,
Oct 13, 2014, 3:25:17 PM10/13/14
to
Il 11/10/2014 23:46, Urs Thuermann ha scritto:
> Is there a way to do this in C++98 without the need to add a new
> function like clone() in each derived class?

Templates and multiple inheritance...

struct Io_obj {
virtual ~Io_obj() {};
virtual Io_obj* clone() const = 0;
};

template<class T>
struct Io : T, Io_obj {
Io* clone() const override { return new Io{*this}; }
};

struct D {};
struct B1 : D {};
struct B2 : D {};

using Io_B1 = Io<B1>;

void f(Io_B1& io_b1) {
B1* b = &io_b1; // deriving from a templ. parameter allows this cast
}

int main() {
Io_B1 b1;
auto b = b1.clone();
f(*b);
}


JiiPee

unread,
Oct 15, 2014, 6:05:34 PM10/15/14
to
On 12/10/2014 01:18, Mr Flibble wrote:
why not dynamic_cast? It would check if the conversion is valid, static
cast does not.

Paavo Helde

unread,
Oct 15, 2014, 10:47:45 PM10/15/14
to
JiiPee <n...@notvalid.com> wrote in news:CcC%v.728797$Fy6.4...@fx25.am4:

> On 12/10/2014 01:18, Mr Flibble wrote:
>> On 12/10/2014 00:55, JiiPee wrote:
>>> void f2(B *b) {
>>> B *b1 = nullptr;
>>> if( typeid(*b).name() == typeid(D1).name() )
>>> b1 = new D1(*(reinterpret_cast<D1*>(b1)));
>>> else if( typeid(*b).name() == typeid(D2).name() )
>>> b1 = new D2(*(reinterpret_cast<D2*>(b1)));
>>> }

You can compare directly typeid-s, no need to fetch out the names
(besides, comparing names is not guaranteed to work, they can all be
empty strings legally IIRC).

>>
>> You should use static_cast not reinterpret_cast when casting from base
>> to derived.
>
> why not dynamic_cast? It would check if the conversion is valid, static
> cast does not.

Dynamic_cast is performed at runtime and can be quite slow. It would be
silly to use dynamic_cast if you have just found out by comparing typeids
that the conversion would be valid (maybe only in debug-build asserts, to
verify you have not made a mistake in the code).

A virtual clone function is still the best solution for the cloning
problem: probably faster than the repeated if-else typeid check and also
more scalable and maintainable.

Cheers
Paavo

Tobias Müller

unread,
Oct 16, 2014, 2:09:15 AM10/16/14
to
JiiPee <n...@notvalid.com> wrote:
> but if for example std::string public interface had a function called:
> B* clone();
> which nobody really uses other than some code internally, then isn't it
> bad from the users point of view seeing this kind of clone function which they never need?
>
> But surely there is a way to hide the clone, like being protected, then
> this would not be a problem.

But clone is quite a fundamental function for polymorphic type hierarchies.
I see no value in hiding that.
Also covariant return types make it look much nicer:

class Base
{
public:
virtual Base* clone();
};

class Derived : public Base
{
virtual Derived* clone();
// instead of:
// virtual Base* clone();
};

This is legal if the return type of the derived function is more specific
than the one of the base function. (Which is always true in the case of
"clone")

Tobi

JiiPee

unread,
Oct 16, 2014, 2:14:32 AM10/16/14
to
On 16/10/2014 03:47, Paavo Helde wrote:
> JiiPee <n...@notvalid.com> wrote in news:CcC%v.728797$Fy6.4...@fx25.am4:
>
>> On 12/10/2014 01:18, Mr Flibble wrote:
>>> On 12/10/2014 00:55, JiiPee wrote:
>>>> void f2(B *b) {
>>>> B *b1 = nullptr;
>>>> if( typeid(*b).name() == typeid(D1).name() )
>>>> b1 = new D1(*(reinterpret_cast<D1*>(b1)));
>>>> else if( typeid(*b).name() == typeid(D2).name() )
>>>> b1 = new D2(*(reinterpret_cast<D2*>(b1)));
>>>> }
> You can compare directly typeid-s, no need to fetch out the names
> (besides, comparing names is not guaranteed to work, they can all be
> empty strings legally IIRC).

sure

>
>>> You should use static_cast not reinterpret_cast when casting from base
>>> to derived.
>> why not dynamic_cast? It would check if the conversion is valid, static
>> cast does not.
> Dynamic_cast is performed at runtime and can be quite slow. It would be
> silly to use dynamic_cast if you have just found out by comparing typeids
> that the conversion would be valid (maybe only in debug-build asserts, to
> verify you have not made a mistake in the code).

yes, did not notice that. Its like using vector [] instead of at() when
we know the size of the vector.

>
> A virtual clone function is still the best solution for the cloning
> problem: probably faster than the repeated if-else typeid check and also
> more scalable and maintainable.
>

Why more scalable? typeid cannot handle all the cases?

JiiPee

unread,
Oct 16, 2014, 2:51:26 AM10/16/14
to
but I was just talking about a hypothetical situation if it was there. I
do not think string::clone would be a good idea for string's public
users, because if clone is needed in some rare cases it can be done for
str just: string(str)

Paavo Helde

unread,
Oct 16, 2014, 3:17:00 AM10/16/14
to
JiiPee <n...@notvalid.com> wrote in news:2nJ%v.461953$177.4...@fx04.am4:
First, adding a new class can be done in a single code place, no need to
modify the common factory-style cloning function in the old code. Some
shops demand multi-week QA testing if any old code is touched.

Second, the new class can be added in a new dynamic load library which
might not even had existed when the common function was written, so could
not be handled by that. Even if it was written, there would appear problems
with circular dependencies (new library should include headers for the old
code, not vice versa).





Paavo Helde

unread,
Oct 16, 2014, 3:21:24 AM10/16/14
to
Paavo Helde <myfir...@osa.pri.ee> wrote in
news:XnsA3C8689492E7Bm...@216.196.109.131:
Oh, and third: typeid comparing has O(N) complexity in respect of the
number of different classes, a virtual function call has O(1) complexity.

Cheers
Paavo

JiiPee

unread,
Oct 16, 2014, 3:46:41 AM10/16/14
to
No just the wording "more scalable" which was confusing me. Isn't it
better to say rather: "better scalable"? Because what you are talking
about here is just that the virtual method is better manageable in the
future....its not that the factory is not able to do the same things,
its just that the virtual method is the better way to do it.

Or are there situations where the factory is not able to do (with good
or bad coding methods) the clones and it can *only* be done by the
virtual method? That was my original question.

If the same thing can be done with both methods (that we get the clone),
then I would not say "is more scalable = more able to be changed in size
(where the size is the ability to get clones)".

JiiPee

unread,
Oct 16, 2014, 3:52:40 AM10/16/14
to
On 16/10/2014 08:16, Paavo Helde wrote:
Can you show me a simple code example where the clone can only be done
by virtual and not factory method?

Paavo Helde

unread,
Oct 16, 2014, 12:24:57 PM10/16/14
to
JiiPee <n...@notvalid.com> wrote in news:pJK%v.537537$Ym.6...@fx05.am4:
> No just the wording "more scalable" which was confusing me. Isn't it
> better to say rather: "better scalable"?

Sorry, not a native speaker - these terms seem the same to me.

Cheers
Paavo

Öö Tiib

unread,
Oct 16, 2014, 12:27:10 PM10/16/14
to
He wrote about modules. C++ does not have modules in its language
description but that is a lie. In practice lot of applications (written in whatever
programming languages) often use modules written in C++. Modules should
not be tightly coupled with each other in all directions otherwise the whole
point of having modules is lost and you have to link them all together
everywhere.

Imagine there is module where base class "Tool" is defined. Imagine it has also
"ToolFactory". Now time passes and you need to develop module for certain
application that needs a tool "Gallows". Result is dependency knot since
"ToolFactory" needs to learn to clone "Gallows". Both modules need to be
linked to all applications that deal with whatever "Tool"s. Crap design since
"Gallows" are used rather rarely. That can be avoided if only "Gallows" know
how to clone "Gallows".

Paavo Helde

unread,
Oct 16, 2014, 12:54:02 PM10/16/14
to
JiiPee <n...@notvalid.com> wrote in news:2PK%v.461970$177....@fx04.am4:

> Can you show me a simple code example where the clone can only be done
> by virtual and not factory method?

Here it goes. Assume that the build process checks out and builds
projects one-by one, in the order specified somewhere else (I have used
such a process for many years in the past), to avoid any fancy ideas of
including b.h in the base library (which would by all wrong conceptually
anyway).


// base library (DLL)
// a.h
class A {
public:
virtual ~A() {}
virtual A* clone() const = 0;
};

void foo(A* x);

// a.cpp
void foo(A* x) {
A* y = x->clone();
delete y;
}

// -------------------------------------

// extension library (DLL) - link to base library
// b.h
//#include <BaseLibrary/a.h>

class B: public A {
public:
virtual B* clone() const override;
};

// b.cpp
B* B::clone() const {
return new B(*this);
}

// -------------------------------------

// main program - link to base library and extension library
// main.cpp

//#include <BaseLibrary/a.h>
//#include <Extensionlibrary/b.h>

int main() {
A* x = new B();
foo(x);
delete x;
}

JiiPee

unread,
Oct 16, 2014, 1:12:02 PM10/16/14
to
They have a bit different meaning. For example making more cars is
different than making better cars. If two people make both 10 cars then
its only a matter who made better cars. If the other one makes 10 cars
and the other one 15 cars, then its a matter of who made better cars
plus who made more cars.

JiiPee

unread,
Oct 16, 2014, 1:17:47 PM10/16/14
to
I do not disagree with virtual method being better. I am only saying
that I cannot see that there would be a situation where the factory
cannot produce the clone and only the virtual method can do it. But
Paavo says he has an example (although there is no explanation), so I ll
try to check that.

JiiPee

unread,
Oct 16, 2014, 1:20:15 PM10/16/14
to
On 16/10/2014 17:53, Paavo Helde wrote:
> JiiPee <n...@notvalid.com> wrote in news:2PK%v.461970$177....@fx04.am4:
>
>> Can you show me a simple code example where the clone can only be done
>> by virtual and not factory method?
> Here it goes. Assume that the build process checks out and builds
> projects one-by one, in the order specified somewhere else (I have used
> such a process for many years in the past), to avoid any fancy ideas of
> including b.h in the base library (which would by all wrong conceptually
> anyway).
>
>

and why factory system cannot do this?

JiiPee

unread,
Oct 16, 2014, 1:35:24 PM10/16/14
to
On 16/10/2014 18:30, Martin Shobe wrote:
> In casual conversation, either works fine. If I was being formal I'd
> say, "... also scales and maintains better ..."
>
> Martin Shobe
>

more apples and better apples are a bit different to me :) ... that was
the confusion I had.
Do we have more apples, or not more but just better apples....

Paavo Helde

unread,
Oct 16, 2014, 1:39:05 PM10/16/14
to
JiiPee <n...@notvalid.com> wrote in news:97T%v.549396$ac7.1...@fx15.am4:
Well, how do you propose to do this? Maybe you could try to write a
replacement for the foo() function which makes a copy of the passed object
without using the virtual clone() function.

Paavo Helde

unread,
Oct 16, 2014, 1:43:08 PM10/16/14
to
JiiPee <n...@notvalid.com> wrote in news:q%S%v.566506$Au1.2...@fx36.am4:
With cars I can see the difference! :) But not with "scalable", here I feel
more==better.

JiiPee

unread,
Oct 16, 2014, 1:49:59 PM10/16/14
to
On 16/10/2014 17:53, Paavo Helde wrote:
> JiiPee <n...@notvalid.com> wrote in news:2PK%v.461970$177....@fx04.am4:
>
>> Can you show me a simple code example where the clone can only be done
>> by virtual and not factory method?
> Here it goes. Assume that the build process checks out and builds
> projects one-by one, in the order specified somewhere else (I have used
> such a process for many years in the past), to avoid any fancy ideas of
> including b.h in the base library (which would by all wrong conceptually
> anyway).
>
>

And why does this factory version of it not work (for example inserting
the factory in main.cpp)? I have not compiled, but seems like it might
work:

// base library (DLL)
// a.h
class A {
public:
virtual ~A() {}
};

// -------------------------------------

// extension library (DLL) - link to base library
// b.h
//#include <BaseLibrary/a.h>

class B: public A {
public:
};

// b.cpp

// -------------------------------------

// main program - link to base library and extension library
// main.cpp

//#include <BaseLibrary/a.h>
//#include <Extensionlibrary/b.h>

A* foo(A *x) {
B *b1 = nullptr;
if( typeid(*x) == typeid(A) )
b1 = new A(*(dynamic_cast<A*>(b1)));
else if( typeid(*x) == typeid(B) )
b1 = new B(*(dynamic_cast<B*>(b1)));

return b1;

JiiPee

unread,
Oct 16, 2014, 1:53:51 PM10/16/14
to
I tried to do that, see my other post....

Paavo Helde

unread,
Oct 16, 2014, 2:04:31 PM10/16/14
to
JiiPee <n...@notvalid.com> wrote in news:0zT%v.467397$Ip7....@fx11.am4:

> And why does this factory version of it not work (for example inserting
> the factory in main.cpp)? I have not compiled, but seems like it might
> work:

You want the factory in the base library, where the foo() function can use
it. The base library is presumably implementing basic functionality which
is working with abstract base class A pointers and doing lots of things
with them, including cloning. If this is not the case, there is no point to
make a class hierarchy with virtual functions in the first place, or to
have dynamically allocated objects at all.


0 new messages