Topic: Require overrides (was virtual sizeof)


Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/02/09
Raw View
Francis Glassborow wrote in message ...

>Several times recently I have come up against cases where (for safety) I
>need to require that every concrete derived class in a hierarchy provide
>its own implementation of a virtual function.  I could live with a
>comparatively high level of expertise placed on the base class
>designer/implementor as long as the result would be a required
>diagnostic for any derived class that breached this invariant.  Any
>ideas?

I think the best way to handle this requirement is to make a strong
distinction between concrete classes and classes intended for derivation.
Classes intended for derivation would remain abstract (=0) with respect to
the
function in question.



As an alternative, here is a hack for a somewhat less strict set of
requirements:

1) We want all concrete classes derived from 'base' to override
     virtual void PrivateMustOverride();

2) We hope that with a name like PrivateMustOverride, implementers of
derived classes will make the function private, if they remember to make it
at all.  If this hope fails we are out of luck.

3) If implementers forget about the requirement entirely, or get the
signature of PrivateMustOverride wrong, they will get a compile time error.

4) If implementers have a typo (misspell PrivateMustOverride), they will get
a run time error as soon as they try to construct a concrete object (run
time error).  I don't think you can make this a required compile-time error.
A constant expression for template arguments can't use pointers.

class mustHave
{
  virtual void PrivateMustOverride() = 0;
  mustHave(const mustHave&);
public:
  template<class T>
  mustHave(void (T::*member)())  // Only accessible constructor
  {
    if(member != &mustHave::PrivateMustOverride)
      Die("You messed up");
  }
  virtual ~mustHave(){}
};

class base: public virtual mustHave { ... };

Any concrete class derived from base must initialize its mustHave base
class.  It has to provide a pointer to a member with the same signature as
PrivateMustOverride or there will be a compile time error.  The pointer it
provides must be an override of PrivateMustOverride or there will be a run
time error.  Assuming every occurrence of PrivateMustOverride is private, a
class won't be able to use some other class's member.  Examples:

// Compile error, doesn't initialize virtual base class
struct c1 : base { c1(); }; c1 a;

// Compile error, trys to access an inaccessible member
struct c2 : base { c2():mustHave(&c2::PrivateMustOverride){} }; c2 b;

// Runtime error, trys to use the wrong function for initialization
class c3 : base
{
  c3(): mustHave(&c3::PrivateOverride){}
private:
  void PrivateOverride();    // Misspelled PrivateMustOverride
};
c3 c;

// Compile error, wrong signature
class c4 : base
{
  c4(): mustHave(&c4::PrivateMustOverride){}
private:
  int PrivateMustOverride();
};
c4 d;

// This one should work
struct c5 : base
{
  c5(): mustHave(&c5::PrivateMustOverride){}
private:
  void PrivateMustOverride();
};
c5 e;

This is pretty ugly IMO.




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]