"Virtual constructor" abstract base class - feasibility?

A

Asfand Yar Qazi

Hi,

I have the following header file in my 'everything useful I think of
in one place' library:

============= BEGIN CODE SNIPPET ===========

/** All classes that derive from this obtain a 'virtual constructor' -
ie if the 'clone()' method is called on a polymorphic type, an
object of the same (unknown) type is returned. */
class CloneService
{
public:
virtual ~CloneService()
{
}

/// This MUST be overridden in children classes. Abstract
/// classes might want to override this too (and keep it
/// abstract), as it will make it more convenient for users to
/// use pointers of those classes.
virtual CloneService*
clone() const = 0;
};

/// Makes it easy to check at compile time if a given template
/// parameter class has the 'clone' method.
template<typename T>
bool
check_clone_service_requirements()
{
T* (T::*test)() const = &T::clone;
test = test;

return true;
}

============= END CODE SNIPPET ===========

Could someone tell me the feasibility of having something like this?
I've used it in a few places and found it useful, but I always do
something like:

class Base : public CloneService
{
// ...
Base* clone() const = 0;
// ...
};

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

i.e. I have to redeclare the clone virtual method in the abstract
virtual base class definition anyway. Can anyone thing of any
situations where having a 'CloneService' base class for all cloneable
classes everywhere would be useful?

And I realise now that the name 'Cloneable' is a better one than
'CloneService' - but that's what using too much Java does to you.

Thanks,
Asfand Yar

--
Entry in RollerCoaster Tycoon 2 readme.txt file:
RollerCoaster Tycoon2 must be played on a video card capable of
640x480 screen resolution at a bit depth setting of 256 bits.
And the proof that playing too many strategy games causes loss of
humour: http://tinyurl.com/dyrtt
 
B

Bob Hairgrove

Hi,

I have the following header file in my 'everything useful I think of
in one place' library:

============= BEGIN CODE SNIPPET ===========

/** All classes that derive from this obtain a 'virtual constructor' -
ie if the 'clone()' method is called on a polymorphic type, an
object of the same (unknown) type is returned. */
class CloneService
{
public:
virtual ~CloneService()
{
}

/// This MUST be overridden in children classes. Abstract
/// classes might want to override this too (and keep it
/// abstract), as it will make it more convenient for users to
/// use pointers of those classes.
virtual CloneService*
clone() const = 0;
};

/// Makes it easy to check at compile time if a given template
/// parameter class has the 'clone' method.
template<typename T>
bool
check_clone_service_requirements()
{
T* (T::*test)() const = &T::clone;
test = test;

return true;
}

============= END CODE SNIPPET ===========

Could someone tell me the feasibility of having something like this?
I've used it in a few places and found it useful, but I always do
something like:

class Base : public CloneService
{
// ...
Base* clone() const = 0;
// ...
};

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

i.e. I have to redeclare the clone virtual method in the abstract
virtual base class definition anyway. Can anyone thing of any
situations where having a 'CloneService' base class for all cloneable
classes everywhere would be useful?

And I realise now that the name 'Cloneable' is a better one than
'CloneService' - but that's what using too much Java does to you.

The problem I see is the fact that clients can now create containers
of pointers to CloneService, although these might be otherwise totally
incompatible types with no other methods in common. IOW, you have the
same design problem as if every single type in your project might
derive from a class called "CObject" (ever heard of MFC?)
 
A

Axter

Asfand said:
Hi,

I have the following header file in my 'everything useful I think of
in one place' library:

============= BEGIN CODE SNIPPET ===========

/** All classes that derive from this obtain a 'virtual constructor' -
ie if the 'clone()' method is called on a polymorphic type, an
object of the same (unknown) type is returned. */
class CloneService
{
public:
virtual ~CloneService()
{
}

/// This MUST be overridden in children classes. Abstract
/// classes might want to override this too (and keep it
/// abstract), as it will make it more convenient for users to
/// use pointers of those classes.
virtual CloneService*
clone() const = 0;
};

/// Makes it easy to check at compile time if a given template
/// parameter class has the 'clone' method.
template<typename T>
bool
check_clone_service_requirements()
{
T* (T::*test)() const = &T::clone;
test = test;

return true;
}

It only makes it easier, if you have the derive type to check it with.
If your pointer does not match the derive type, then the above code
will fail to catch the error at compile time.
It's still better then nothing, but it's not fail proof.
I use a similar method in the following policy class smart pointer:
http://code.axter.com/smart_ptr.h

If you look at the clone_static_function_allocator_policy, you'll see
that it uses a static clone function, instead of the normal virtual
clone function.

If a derived type is used that doesn't have the static function
declared, it will cause a compile time error.
But this method also is not fail proof, since a derived pointer could
be used to a derived-derived type, and than it will fail to produce an
error if the derived-derived type has no clone function.
 
A

Asfand Yar Qazi

Bob Hairgrove wrote:
The problem I see is the fact that clients can now create containers
of pointers to CloneService, although these might be otherwise totally
incompatible types with no other methods in common. IOW, you have the
same design problem as if every single type in your project might
derive from a class called "CObject" (ever heard of MFC?)

Ah - I see. From now on, I will simply declare the virtual clone() function in
every base class I produce, and they will be totally unrelated in terms of
ancestry. Thanks for the advice

--
Entry in RollerCoaster Tycoon 2 readme.txt file:
RollerCoaster Tycoon2 must be played on a video card capable of 640x480 screen
resolution at a bit depth setting of 256 bits.
And the proof that playing too many strategy games causes loss of humour:
http://tinyurl.com/dyrtt
 
S

Shark

Asfand said:
Bob Hairgrove wrote:


Ah - I see. From now on, I will simply declare the virtual clone() function in
every base class I produce, and they will be totally unrelated in terms of
ancestry. Thanks for the advice

I think clone() has more to do with prototype design pattern than with
virtual constructor (factory design pattern). Ask in comp.object too.
 
L

Luke Meyers

Asfand said:
i.e. I have to redeclare the clone virtual method in the abstract
virtual base class definition anyway. Can anyone thing of any
situations where having a 'CloneService' base class for all cloneable
classes everywhere would be useful?

I don't think it's useful, for the same reason that there isn't a
common std::eek:bject base class, or even a common base class for all STL
iterators. You're free to define clone() methods wherever you need
them. Having a common parent which requires this (and doesn't solve
the problem of multi-level inheritance) only allows you to treat all
such objects polymorphically. Is there some OO justification for
treating completely unrelated classes polymorphically? Not in any
defensible design, I think.

But yeah, tell that to Java.

Look into compile-time polymorphism with templates. It accomplishes
what you're trying to do, without necessitating meaningless
inheritance. Once you grasp the point that inheritance is far from the
only kind of relationship between types, you'll be a much happier
coder.

Oh, and read some books from the "C++ In-Depth" series, particularly
Alexandrescu and Sutter.

Luke
 
A

Asfand Yar Qazi

Luke said:
Look into compile-time polymorphism with templates. It accomplishes
what you're trying to do, without necessitating meaningless
inheritance. Once you grasp the point that inheritance is far from the
only kind of relationship between types, you'll be a much happier
coder.

Sometimes I need to clone something that I know the base type of, but do not
know what the object actually is. That's what I need a virtual constructor (or
whatever the design pattern people call it).
Oh, and read some books from the "C++ In-Depth" series, particularly
Alexandrescu and Sutter.

Will do.

--
Entry in RollerCoaster Tycoon 2 readme.txt file:
RollerCoaster Tycoon2 must be played on a video card capable of 640x480 screen
resolution at a bit depth setting of 256 bits.
And the proof that playing too many strategy games causes loss of humour:
http://tinyurl.com/dyrtt
 
L

Luke Meyers

Asfand said:
Sometimes I need to clone something that I know the base type of, but do not
know what the object actually is. That's what I need a virtual constructor (or
whatever the design pattern people call it).

Right, and that's fine. Because you know the base type, you can see
the base type's virtual clone() member function and use it. That
provides exactly what you'd want. Introducing a separate Cloneable
parent just complicates the situation and gains you nothing.

Luke
 

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,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top