3

I have to add common functionality to some classes that share the same superclass, preferably without bloating the superclass. The simplified inheritance chain looks like this:

Element -> HTMLElement -> HTMLAnchorElement
Element -> SVGElement -> SVGAlement

The default doSomething() method on Element is no-op by default, but there are some subclasses that need an actual implementation that requires some extra overridden methods and instance members. I cannot put a full implementation of doSomething() in Element because 1) it is only relevant for some of the subclasses, 2) its implementation has a performance impact and 3) it depends on a method that could be overridden by a class in the inheritance chain between the superclass and a subclass, e.g. SVGElement in my example.

Especially because of the third point, I wanted to solve the problem using a template class, as follows (it is a kind of decorator for classes):

struct Element {
 virtual void doSomething() {}
};
// T should be an instance of Element
template<class T>
struct AugmentedElement : public T {
 // doSomething is expensive and uses T
 virtual void doSomething() override {}
 // Used by doSomething
 virtual bool shouldDoSomething() = 0;
};
class SVGElement : public Element { /* ... */ };
class SVGAElement : public AugmentedElement<SVGElement> {
 // some non-trivial check
 bool shouldDoSomething() { /* ... */ return true; }
};
// Similarly for HTMLAElement and others

I looked around (in the existing (huge) codebase and on the internet), but didn't find any similar code snippets, let alone an evaluation of the effectiveness and pitfalls of this approach.

Is my design the right way to go, or is there a better way to add common functionality to some subclasses of a given superclass?

asked Aug 21, 2014 at 15:22

1 Answer 1

3

You are doing it correctly. The thing is called a mixin and is rather common.

Quick search shows e.g. What are Mixins (as a concept) or What is C++ Mixin-Style?. They are a case of the Curiously Recurring Template Pattern, name of which even comes from the fact that it is, well, recurring.

In your case actually using full CRTP would let you avoid the virtual:

template<typename BaseT, typename DerivedT>
struct AugmentedElement : public BaseT {
 // doSomething is expensive and uses T
 virtual void doSomething() override {
 // do stuff
 static_cast<DerivedT *>(this)->shouldDoSomething();
 // do more stuff, etc.
 }
};
answered Aug 21, 2014 at 15:56
2
  • I thought that a mixin was an extension to a superclass rather than an override. Is that incorrect? Thanks for mentioning CRTP, I left it out of the question because I thought that it was not relevant, but with your example the name seems to make more sense. PS. "T" should be changed to "BaseT" in your example. Commented Aug 21, 2014 at 16:30
  • @RobW: Mixin is any template that you inject into the inheritance chain. Commented Aug 21, 2014 at 18:18

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.