Hacker News new | past | comments | ask | show | jobs | submit login
How to Emulate the “super” Keyword in C++ (fluentcpp.com)
40 points by joboccara on Dec 26, 2017 | hide | past | favorite | 15 comments



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.


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


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.


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".


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).


> 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.)


“…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.


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?


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.


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.


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.


In D, I just call super.this(var, var) to ensure I'm calling the correct base constructor. And fire off an assert if super(void) gets called because I didn't explicitly write a specialized one.

But I think C++ has what... parameter lists for that?


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


  base_type::draw()
analogous to Java's super.draw()


This blog is always worth a read.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: