[comp.lang.c++] Abstract Base Class Enforcement

wohlenbe@intertel.UUCP (Greg Wohlenberg) (03/23/91)

Hi,

     I've  got  a question.   Say you have  a base  class that  you want to be
abstract.  But, for one reason or another, it  isn't convenient to make any of
the  class's virtual functions  pure.  (This would happen  if all your virtual
functions actually "do something" in the base class.)  Given that you  want to
disallow instances of  the abstract base  class from  being created, which  of
these alternatives is best?

1. Create a extra do-nothing function in the base class that is pure virtual.

2. Make the base class's no-parameter constructor "protected".  This  makes it
so only  derived classes  are able to create instances  of the base class (and
therefore enforces the abstract characteristic of the base class).

     Or, is there another alternative that I am not aware of?

Thanks,

Greg Wohlenberg          |    Voice: (602) 961-9000
Inter-tel, Inc.          |      Fax: (602) 961-1370
6505 W. Chandler Blvd.   | INTERNET: wohlenbe%intertel.uucp@asuvax.eas.asu.edu
Chandler, Arizona, 85226 |     UUCP: intertel!wohlenbe@asuvax.eas.asu.edu

wmm@world.std.com (William M Miller) (03/25/91)

wohlenbe@intertel.UUCP (Greg Wohlenberg) writes:
>      I've  got  a question.   Say you have  a base  class that  you want to be
> abstract.  But, for one reason or another, it  isn't convenient to make any of
> the  class's virtual functions  pure.  (This would happen  if all your virtual
> functions actually "do something" in the base class.)

If you mean that it's all right for a derived class to override none of the
base class's virtual functions, then you do need one of the additional
methods you described or the one I'll mention below.  However, if you mean
that you need a definition in the base class to provide some common
processing that can be used by derived class overriding functions, there's
nothing to stop you from providing a definition for a pure virtual function;
it will never be invoked by an ordinary member function call, but an
explicitly-qualified call (e.g., "Base::pure_virt1()") will invoke the base
class definition.

> 1. Create a extra do-nothing function in the base class that is pure virtual.
>
> 2. Make the base class's no-parameter constructor "protected".  This  makes it
> so only  derived classes  are able to create instances  of the base class (and
> therefore enforces the abstract characteristic of the base class).

Actually, you'd need to make *all* the constructors either protected or
private.

>      Or, is there another alternative that I am not aware of?

How about making the destructor pure?  (I assume it's already virtual; the
rule of thumb is to make the destructor virtual if there are any virtual
functions.)  You still have to provide a definition of it or the program
won't link or run, of course.

-- William M. Miller, Glockenspiel, Ltd.
   wmm@world.std.com

dag@control.lth.se (Dag Bruck) (03/25/91)

In article <1991Mar24.204943.9998@world.std.com> wmm@world.std.com (William M Miller) writes:
>
>Actually, you'd need to make *all* the constructors either protected or
>private.

You may want to keep the copy-constructor public.

		-- Dag Br\"uck

wmm@world.std.com (William M Miller) (03/25/91)

dag@control.lth.se (Dag Bruck) writes:
> >Actually, you'd need to make *all* the constructors either protected or
> >private.
>
> You may want to keep the copy-constructor public.

No.  Remember that the goal was to make an abstract base class, i.e., a
class of which there could be no objects.  Therefore you can't have by-value
arguments and other contexts in which a copy constructor might be invoked;
the only way a copy constructor can be legitimately invoked for an abstract
base class is from the copy constructor of a derived class, copying the base
class subobject of a derived class object, and protected access is
sufficient for this case.

-- William M. Miller, Glockenspiel, Ltd.
   wmm@world.std.com

wmm@ (&.std.com (William M Miller)) (03/26/91)

dag@control.lth.se (Dag Bruck) writes:
> >Actually, you'd need to make *all* the constructors either protected or
> >private.
>
> You may want to keep the copy-constructor public.

No.  Remember that the goal was to make an abstract base class, i.e., a
class of which there could be no objects.  Therefore you can't have by-value
arguments and other contexts in which a copy constructor might be invoked;
the only way a copy constructor can be legitimately invoked for an abstract
base class is from the copy constructor of a derived class, copying the base
class subobjllindf a derived class object, and protected access is
sufficient for this case.

-- William M. Miller, Glockenspiel, Ltd.
   wmm@(orld.std.com
#! rnews 781
6.15ican be pws!ccut!sun-Uarr!olivea!oamsung!zaphod.mps.ohio-state.edu!wuarch

linton@sgi.com (Mark Linton) (03/26/91)

In article <358@intertel.UUCP>, wohlenbe@intertel.UUCP (Greg Wohlenberg) writes:
|>      I've  got  a question.   Say you have  a base  class that  you want to be
|> abstract.  But, for one reason or another, it  isn't convenient to make any of
|> the  class's virtual functions  pure.  (This would happen  if all your virtual
|> functions actually "do something" in the base class.)  Given that you  want to
|> disallow instances of  the abstract base  class from  being created, which  of
|> these alternatives is best?
|> 
|> 1. Create a extra do-nothing function in the base class that is pure virtual.
|> 
|> 2. Make the base class's no-parameter constructor "protected".  This  makes it
|> so only  derived classes  are able to create instances  of the base class (and
|> therefore enforces the abstract characteristic of the base class).

Use option 2, making all constructors protected (define a protected no-parameter
constructor if the class otherwise has no constructors).  Adding an unnecessary
pure virtual would confuse people.  Pure virtual means subclasses must provide
an implementation, which is not what you intend.  Similarly, a pure virtual destructor,
if that works, is not what you want (you needn't force subclasses to define a destructor).

Unfortunately, section 10.3 of the ARM confuses people with the statement

    A class is abstract if it has at least one pure virtual function.

This statement is correct, but many people interpret the "if" to mean "if and only if",
which is not correct.  All classes with pure virtual functions are abstract, but not
all abstract classes have a pure virtual function.