
How to Emulate the “super” Keyword in C++ - joboccara
https://www.fluentcpp.com/2017/12/26/emulate-super-base/
======
cjensen
There was a proposal for a super/inherited keyword in C++. It was immediately
killed when Michael Tiemann demonstrated this technique of adding it manually
via typedef in the base class.

As others have pointed out, putting the keyword in the base class is Highly
Questionable.

~~~
stingraycharles
Doesn’t that imply that the typedef technique is not a good replacement for
super?

------
emmelaich
As an aside, isn't it silly to describe the same thing as both a _base_
(below) class and _super_ (above). I think I'd prefer parent/child.

I've also seen inconsistency in various inheritance diagrams; sometimes the
arrow points to the child, sometimes to the parent.

~~~
int_19h
Parent/child usually refers to ownership relationships between objects,
though, not classes. As in, an item is a child of a collection.

On the other hand, there's nothing wrong with "super", given that it stands
for "superclass", which has a well-defined meaning. For that matter, so does
"base class".

------
KonkeyDong69
I would caution against using this pattern. In particular, this does not scale
to:

    
    
        class A {};
        class B : public A {};
        class C : public B {};
    

Using the convention of defining `base_type` in the base class means that C
will expect B to define `base_type`, which means that B will be cut off from
A's `base_type`. This then forces you to use different identifiers, which
brings you back to square one (you might as well just explicitly write out the
class in that case).

~~~
Koshkin
> _brings you back to square one_

Not exactly, since C's constructor does not call A's directly. (On the other
hand, base_class::base_class might just do the trick.)

------
evincarofautumn
“…for bases classes with a long name, repeating it in the body of the derived
class adds a lot of clutter to it.”

When you _write_ the code, it feels a bit cumbersome. When you _read_ it,
though, you know exactly what’s going on—which pays over and over again. These
days, for most code in any language, I’m more inclined to say to myself “suck
it up and be explicit” when it comes to these small decisions—as long as
“explicit” doesn’t get confused with “needlessly long-winded”, of course.

------
SeanBoocock
This is a good overview of the ways to deal with this in C++. However, I often
run into situations in large code bases with deep inheritance heirarchies
where calling Super::Foo() on virtual methods is necessary for correct
functionality and a frequent source of bugs.

To the extent that I have control over the architecture, I prefer flat
hierarchies with pure virtuals and final implementations, but what are good
approaches to solving this issue for deeper class hierarchies? Is there a good
alternative to the pseudo Super if Class A, B, C, and D each need to twiddle
some state when you call ::Foo() on an object of type E?

~~~
Waterluvian
Personally I have yet to find a real-world practical example of a deep
hierarchy that felt like an intuitive, natural approach to solving the given
problem. I'm not specifically skeptical of their existence, but I do question
if maybe the problem with deep hierarchies is addressed by not using them.

~~~
SeanBoocock
Oh I quite agree that in general having a deep inheritance hierarchy is not
ideal and that many problems can better be solved with compartmentalization or
other approaches. I was asking more in the context of you have a million+ line
code base and want to make things less error prone/cleaner without refactoring
large chunks of it.

~~~
sounds
Though this is not the only solution, a visitor pattern seems to match.

I can think of other possibilities; hopefully this sparks some good ideas for
you. I'll sketch up how I think the visitor pattern could work, sorry if it's
already obvious:

Base class A. Derived classes B, C, and D.

When A::Foo() is called run code from each class, in the order they are
initialized.

    
    
      class A {
      protected:
        vector<function<void(int)>> visitFoo;
      public:
        void Foo(int bar) {
          for (auto fn : visitFoo) {
            fn(bar);
          }
        }
      };
    
      class B : public A {
      protected:
        // Do not override Foo in class B, C, or D.
        void FooB(int bar) {
        }
      public:
        B() {
          // visitor pattern
          visitFoo.emplace_back(FooB);
        }
      };
    

Repeat for C and D.

------
slokki
Didn't quite get this. Where is the emulation of super itself? Expected
something like auto super = static_cast<base_type*>(this)...

~~~
richardwhiuk

      base_type::draw()
    

analogous to Java's super.draw()

------
biocomputation
This blog is always worth a read.

