Enforcing Inheritance Rules
September 18th, 2009
While writing C++ sometimes one wishes that one could squeeze a little more out of the type system. In this particular case, Zack Weinberg (layout-refactorer extraordinaire), wanted to make sure that certain methods always get overridden in derived classes. Unfortunately, in that particular design, those methods were not pure-virtual. At this point most C++ hackers would cry a little and move on without any compiler assistance.
Instead of crying, Zack added a NS_MUST_OVERRIDE attribute to methods along with a matching Dehydra script. See the source code and the bug for how simple it can be to extend C++ with a useful new check.
Nothing makes me happier than seeing developers land big code changes and accompany them with compiler checks instead of relying on programming folklore to maintain important invariants.
September 19th, 2009 at 1:01 am
Hi,
Maybe I missed something but why did he not just make the member function pure-virtual? I mean the function is already virtual and because the new attribute requires the class to be modified I do not really see why one could not just add ‘= 0′.
Of course by making it pure-virtual the base class cannot be instantiated anymore, however instantiating a class with NS_MUST_OVERRIDE cannot (?) be well-defined anyway otherwise the ‘_MUST_’ doesn’t really make any sense.
Please enlighten me,
With kind regards,
Mikael Olenfalk
September 19th, 2009 at 9:56 am
Overriding isn’t only about replacing methods. OO design also involves calling the same method on the superclass to do involve functionality common to all of the method implementations
September 25th, 2009 at 4:17 am
Wouldn’t this solve the issue just as well?
class A {
public:
virtual void must_implement() = 0;
};
void A::must_implement ()
{ do_common_stuff(); }
class B : public A {
public:
virtual void must_implement()
{ A::do_common_stuff(); do_more_stuff(); }
};
September 25th, 2009 at 4:19 am
Sorry, I found a typo in my last comment:
The body for B::must_implement() should of course call A::must_implement() and not A::do_common_stuff():
class B : public A {
public:
virtual void must_implement()
{ A::must_implement(); do_more_stuff(); }
};