5 ms·
How to Emulate the “super” Keyword in C++
- biocomputation 9y agoThis blog is always worth a read.
- slokki 9y agoDidn't quite get this. Where is the emulation of super itself? Expected something like auto super = static_cast<base_type*>(this)...
- richardwhiuk 9y agobase_type::draw() analogous to Java's super.draw()
- dagobert63 9y agoMSVC also gives you a __super keyword that basically does this but it is not portable of course. https://msdn.microsoft.com/en-us/library/94dw1w7x.aspx https://msdn.microsoft.com/en-us/library/94dw1w7x.aspx
- KonkeyDong69 9y agoI 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 9y ago> 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.)
- cjensen 9y agoThere 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 9y agoDoesn’t that imply that the typedef technique is not a good replacement for super?
- emmelaich 9y agoAs 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 9y agoParent/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".
- deleted 9y ago[deleted]
- SeanBoocock 9y agoThis 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 9y agoPersonally 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.
- katastic 9y agoIn 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?
- SeanBoocock 9y agoOh 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 9y agoThough 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.
- evincarofautumn 9y ago“…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.